CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-stix2-validator

APIs and scripts for validating STIX 2.x documents against specification requirements and best practices.

Overview
Eval results
Files

exception-handling.mddocs/

Exception Handling

Comprehensive exception hierarchy for different validation error scenarios, enabling precise error handling and programmatic response to validation failures.

Capabilities

Base Exception Classes

Core exception types that form the foundation of the STIX validator's error handling system.

class ValidationError(Exception):
    """
    Base Exception for all validator-specific exceptions.
    
    Description:
    This can be used directly as a generic Exception or as a base class
    for more specific validation errors. All validator-specific exceptions
    inherit from this class.
    """
    pass

Example Usage:

from stix2validator import validate_string, ValidationError

try:
    result = validate_string('{"invalid": "json"}')
except ValidationError as e:
    print(f"Validation error occurred: {e}")
    # Handle any validator-specific error
except Exception as e:
    print(f"Unexpected error: {e}")

Schema-Related Exceptions

Exceptions specifically related to JSON Schema validation and schema file issues.

class SchemaInvalidError(ValidationError):
    """
    Represent an error with the JSON Schema file itself.
    
    Description:
    Raised when there are problems with the STIX JSON schema files
    used for validation, such as malformed schema definitions or
    missing schema components.
    """
    pass

class SchemaError(ValidationError):
    """
    Represent a JSON Schema validation error.
    
    Parameters:
    - error: An error returned from JSON Schema validation
    
    Attributes:
    - message: The JSON validation error message
    
    Methods:
    - as_dict(): Returns a dictionary representation
    - __str__(): Returns string representation of the message
    """
    
    def __init__(self, error):
        pass
    
    def as_dict(self):
        """Return dictionary representation of the schema error."""
        pass
    
    def __str__(self):
        """Return string representation of the error message."""
        pass

Example Usage:

from stix2validator import validate_instance, SchemaError, SchemaInvalidError

# Example STIX object with schema violations
invalid_stix = {
    "type": "indicator",
    "id": "not-a-valid-uuid",  # Invalid UUID format
    "pattern": "[file:hashes.MD5 = 'invalid']",
    "labels": "not-a-list"  # Should be a list
}

try:
    result = validate_instance(invalid_stix)
    if not result.get('valid'):
        for error in result.get('errors', []):
            if isinstance(error, SchemaError):
                print(f"Schema validation error: {error.message}")
                print(f"Error details: {error.as_dict()}")

except SchemaInvalidError as e:
    print(f"Schema file problem: {e}")
    # Handle issues with schema files themselves

except SchemaError as e:
    print(f"Schema validation failed: {e}")
    # Handle specific schema validation failures

Pattern Validation Exceptions

Specialized exceptions for STIX pattern validation issues.

class PatternError(schema_exceptions.ValidationError):
    """
    Represent a problem with a STIX Pattern.
    
    Parameters:
    - msg (str, optional): Error message (default: None)
    - instance_id (str, optional): Instance identifier (default: None)
    
    Description:
    Raised when STIX indicator patterns fail to validate against
    the STIX pattern grammar or contain syntax errors.
    """
    
    def __init__(self, msg=None, instance_id=None):
        pass

Example Usage:

from stix2validator import validate_string, PatternError

# STIX indicator with invalid pattern
invalid_pattern = '''
{
    "type": "indicator",
    "spec_version": "2.1",
    "id": "indicator--12345678-1234-1234-1234-123456789012",
    "created": "2023-01-01T00:00:00.000Z",
    "modified": "2023-01-01T00:00:00.000Z",
    "pattern": "[invalid-pattern-syntax]",
    "labels": ["malicious-activity"]
}
'''

try:
    result = validate_string(invalid_pattern)
    if not result.is_valid:
        for error in result.errors:
            if "Pattern" in str(error):
                print(f"Pattern validation failed: {error}")

except PatternError as e:
    print(f"STIX pattern error: {e}")
    # Handle pattern-specific validation failures

File System Exceptions

Exceptions related to file I/O operations during validation.

class NoJSONFileFoundError(OSError):
    """
    Represent a problem finding the input JSON file(s).
    
    Description:
    Raised when specified JSON files cannot be found or accessed
    during file-based validation operations.
    """
    pass

Example Usage:

from stix2validator import validate_file, NoJSONFileFoundError

files_to_validate = [
    "existing_file.json",
    "missing_file.json",
    "inaccessible_file.json"
]

for filename in files_to_validate:
    try:
        result = validate_file(filename)
        print(f"✓ {filename}: {'Valid' if result.is_valid else 'Invalid'}")
        
    except NoJSONFileFoundError as e:
        print(f"✗ {filename}: File not found - {e}")
    
    except PermissionError as e:
        print(f"✗ {filename}: Permission denied - {e}")
    
    except ValidationError as e:
        print(f"✗ {filename}: Validation error - {e}")

Error Formatting Utilities

Helper functions for formatting and presenting validation errors in a user-friendly manner.

def pretty_error(error, verbose=False):
    """
    Return an error message that is easier to read and more useful.
    
    Parameters:
    - error: The error object to format
    - verbose (bool): Whether to include verbose error information (default: False)
    
    Returns:
    str: A formatted error message that is easier to read and more useful
    
    Description:
    Transforms technical validation error messages into more readable
    and actionable error descriptions. May require updating if the
    schemas change significantly.
    """

def remove_u(input):
    """
    Remove ugly u'' prefixes from input string.
    
    Parameters:
    - input (str): Input string potentially containing u'' prefixes
    
    Returns:
    str: String with u'' prefixes removed
    
    Description:
    Utility function for cleaning up string representations by removing
    Python 2 style unicode prefixes from error messages and output.
    """

Example Usage:

from stix2validator import validate_string
from stix2validator.errors import pretty_error, remove_u

# Validate STIX with errors
stix_with_errors = '''
{
    "type": "indicator",
    "spec_version": "2.1",
    "id": "invalid-uuid-format",
    "created": "not-a-timestamp",
    "modified": "2023-01-01T00:00:00.000Z",
    "pattern": "[file:hashes.MD5 = 'hash']",
    "labels": ["malicious-activity"]
}
'''

result = validate_string(stix_with_errors)

if not result.is_valid:
    for error in result.errors:
        # Format error for better readability
        formatted_error = pretty_error(error, verbose=True)
        print(f"Formatted error: {formatted_error}")
        
        # Compare with raw error
        print(f"Raw error: {error}")
        print("---")

# Example of remove_u utility function
raw_error_message = "u'invalid' does not match u'pattern'"
cleaned_message = remove_u(raw_error_message)
print(f"Raw: {raw_error_message}")
print(f"Cleaned: {cleaned_message}")

Advanced Exception Handling Patterns

Comprehensive Error Handling

from stix2validator import (
    validate_file, validate_string, validate_instance,
    ValidationError, SchemaError, SchemaInvalidError, 
    NoJSONFileFoundError, PatternError
)
from stix2validator.errors import pretty_error
import json

def robust_stix_validation(input_data, input_type="string"):
    """
    Comprehensive STIX validation with detailed error handling.
    
    Parameters:
    - input_data: STIX data (string, dict, or filename)
    - input_type: Type of input ("string", "instance", "file")
    
    Returns:
    dict: Validation results with detailed error information
    """
    result_info = {
        "valid": False,
        "errors": [],
        "warnings": [],
        "error_types": [],
        "input_type": input_type
    }
    
    try:
        # Select appropriate validation function
        if input_type == "file":
            result = validate_file(input_data)
        elif input_type == "string":
            result = validate_string(input_data)
        elif input_type == "instance":
            result = validate_instance(input_data)
        else:
            raise ValueError(f"Invalid input_type: {input_type}")
        
        # Process results
        result_info["valid"] = result.is_valid
        
        if hasattr(result, 'object_results'):
            # File validation results
            for obj_result in result.object_results:
                if obj_result.errors:
                    for error in obj_result.errors:
                        formatted_error = pretty_error(error, verbose=True)
                        result_info["errors"].append(formatted_error)
                        result_info["error_types"].append(type(error).__name__)
                
                if obj_result.warnings:
                    result_info["warnings"].extend(obj_result.warnings)
        else:
            # Object validation results
            if hasattr(result, 'errors') and result.errors:
                for error in result.errors:
                    formatted_error = pretty_error(error, verbose=True)
                    result_info["errors"].append(formatted_error)
                    result_info["error_types"].append(type(error).__name__)
            
            if hasattr(result, 'warnings') and result.warnings:
                result_info["warnings"].extend(result.warnings)
    
    except NoJSONFileFoundError as e:
        result_info["errors"].append(f"File not found: {e}")
        result_info["error_types"].append("NoJSONFileFoundError")
    
    except SchemaInvalidError as e:
        result_info["errors"].append(f"Schema file error: {e}")
        result_info["error_types"].append("SchemaInvalidError")
    
    except SchemaError as e:
        result_info["errors"].append(f"Schema validation error: {e.message}")
        result_info["error_types"].append("SchemaError")
    
    except PatternError as e:
        result_info["errors"].append(f"Pattern error: {e}")
        result_info["error_types"].append("PatternError")
    
    except json.JSONDecodeError as e:
        result_info["errors"].append(f"JSON parsing error: {e}")
        result_info["error_types"].append("JSONDecodeError")
    
    except ValidationError as e:
        result_info["errors"].append(f"Validation error: {e}")
        result_info["error_types"].append("ValidationError")
    
    except Exception as e:
        result_info["errors"].append(f"Unexpected error: {e}")
        result_info["error_types"].append(type(e).__name__)
    
    return result_info

# Usage examples
print("=== File Validation ===")
file_result = robust_stix_validation("threat_data.json", "file")
print(f"Valid: {file_result['valid']}")
for error in file_result["errors"]:
    print(f"Error: {error}")

print("\n=== String Validation ===")
stix_string = '{"type": "malware", "name": "BadMalware", ...}'
string_result = robust_stix_validation(stix_string, "string")
print(f"Valid: {string_result['valid']}")

print("\n=== Instance Validation ===")
stix_dict = {"type": "threat-actor", "name": "APT Group", "labels": ["hacker"]}
instance_result = robust_stix_validation(stix_dict, "instance")
print(f"Valid: {instance_result['valid']}")

Error Recovery and Retry Logic

import time
from stix2validator import validate_file, ValidationError, NoJSONFileFoundError

def validate_with_retry(filename, max_retries=3, retry_delay=1.0):
    """
    Validate STIX file with retry logic for transient errors.
    """
    for attempt in range(max_retries):
        try:
            result = validate_file(filename)
            return result
        
        except NoJSONFileFoundError:
            # Don't retry for file not found
            raise
        
        except ValidationError as e:
            if "schema" in str(e).lower() and attempt < max_retries - 1:
                # Retry schema-related errors (might be transient)
                print(f"Schema error on attempt {attempt + 1}, retrying...")
                time.sleep(retry_delay)
                continue
            else:
                # Re-raise if max retries reached or non-retryable error
                raise
        
        except Exception as e:
            if attempt < max_retries - 1:
                print(f"Unexpected error on attempt {attempt + 1}, retrying...")
                time.sleep(retry_delay)
                continue
            else:
                raise
    
    raise ValidationError(f"Validation failed after {max_retries} attempts")

# Usage
try:
    result = validate_with_retry("unreliable_file.json")
    print(f"Validation successful after retries: {result.is_valid}")
except Exception as e:
    print(f"Final validation failure: {e}")

Context-Aware Error Handling

from contextlib import contextmanager
from stix2validator import ValidationError

@contextmanager
def stix_validation_context(operation_name="STIX validation"):
    """
    Context manager for enhanced error handling during STIX validation.
    """
    try:
        print(f"Starting {operation_name}...")
        yield
        print(f"Completed {operation_name} successfully")
    
    except NoJSONFileFoundError as e:
        print(f"File access error during {operation_name}: {e}")
        raise
    
    except ValidationError as e:
        print(f"Validation failed during {operation_name}: {e}")
        raise
    
    except Exception as e:
        print(f"Unexpected error during {operation_name}: {e}")
        raise

# Usage
with stix_validation_context("Threat intelligence validation"):
    results = validate_file("threat_intel.json")
    if not results.is_valid:
        # Handle validation failures within context
        handle_validation_errors(results)

Install with Tessl CLI

npx tessl i tessl/pypi-stix2-validator

docs

cli-utilities.md

configuration.md

core-validation.md

exception-handling.md

index.md

results-output.md

tile.json