GraphQL-core is a Python port of GraphQL.js, the JavaScript reference implementation for GraphQL.
—
Handle GraphQL errors with location information, formatted error responses, and extensible error reporting. Provides comprehensive error management for GraphQL operations with detailed debugging information.
Primary error class for all GraphQL-related errors with location tracking and extensible metadata.
class GraphQLError(Exception):
def __init__(
self,
message: str,
nodes: Optional[Union[Node, Sequence[Node]]] = None,
source: Optional[Source] = None,
positions: Optional[Sequence[int]] = None,
path: Optional[Sequence[Union[str, int]]] = None,
original_error: Optional[Exception] = None,
extensions: Optional[Dict[str, Any]] = None,
)
message: str
locations: Optional[List[SourceLocation]]
path: Optional[List[Union[str, int]]]
nodes: Optional[List[Node]]
source: Optional[Source]
positions: Optional[List[int]]
original_error: Optional[Exception]
extensions: Optional[Dict[str, Any]]
def formatted(self) -> GraphQLFormattedError
def __str__(self) -> strProperties:
message: Human-readable error descriptionlocations: Source locations where error occurredpath: Path to the field that caused the errornodes: AST nodes associated with the errorsource: GraphQL source documentpositions: Character positions in sourceoriginal_error: Underlying Python exception if anyextensions: Additional error metadatafrom graphql import GraphQLError, Source
# Basic error
error = GraphQLError("Something went wrong")
print(error.message) # "Something went wrong"
# Error with location information
source = Source('query { user { name } }')
error_with_location = GraphQLError(
"Field 'name' not found",
source=source,
positions=[15]
)
print(error_with_location.locations[0].line) # Line number
print(error_with_location.locations[0].column) # Column number
# Error with path information
path_error = GraphQLError(
"Cannot resolve field",
path=['user', 'profile', 'avatar']
)
print(path_error.path) # ['user', 'profile', 'avatar']
# Error with extensions
extended_error = GraphQLError(
"Access denied",
extensions={'code': 'FORBIDDEN', 'userId': '123'}
)
print(extended_error.extensions) # {'code': 'FORBIDDEN', 'userId': '123'}Specialized error class for GraphQL syntax and parsing errors.
class GraphQLSyntaxError(GraphQLError):
def __init__(
self,
source: Source,
position: int,
description: str,
)from graphql import parse, GraphQLSyntaxError
try:
parse('query { user { name }') # Missing closing brace
except GraphQLSyntaxError as e:
print(f"Syntax error: {e.message}")
print(f"At line {e.locations[0].line}, column {e.locations[0].column}")Convert regular Python exceptions into GraphQL errors with location context.
def located_error(
original_error: Exception,
nodes: Optional[Union[Node, Sequence[Node]]] = None,
path: Optional[Sequence[Union[str, int]]] = None,
) -> GraphQLErrorfrom graphql import located_error
def risky_resolver(obj, info):
try:
return perform_database_operation()
except DatabaseError as e:
# Convert to GraphQL error with location
raise located_error(e, info.field_nodes, info.path)
# Or in middleware
class ErrorHandlingMiddleware:
def resolve(self, next_resolver, root, info, **args):
try:
return next_resolver(root, info, **args)
except Exception as e:
# Ensure all errors have location context
if not isinstance(e, GraphQLError):
e = located_error(e, info.field_nodes, info.path)
raise eFormat errors for client consumption with standardized structure.
# Error format types
GraphQLFormattedError = Dict[str, Any]
GraphQLErrorExtensions = Dict[str, Any]
# Format error manually
def format_error(error: GraphQLError) -> GraphQLFormattedError:
formatted = {'message': error.message}
if error.locations:
formatted['locations'] = [
{'line': loc.line, 'column': loc.column}
for loc in error.locations
]
if error.path:
formatted['path'] = error.path
if error.extensions:
formatted['extensions'] = error.extensions
return formattedfrom graphql import GraphQLError
error = GraphQLError(
"User not found",
path=['user'],
extensions={'code': 'NOT_FOUND', 'userId': '123'}
)
formatted = error.formatted()
print(formatted)
# {
# 'message': 'User not found',
# 'path': ['user'],
# 'extensions': {'code': 'NOT_FOUND', 'userId': '123'}
# }Best practices for handling errors in resolver functions.
from graphql import GraphQLError
# Return None for missing data (becomes null in response)
def resolve_optional_field(obj, info):
user = get_user_by_id(obj.user_id)
if not user:
return None # Field becomes null
return user.name
# Raise GraphQLError for validation errors
def resolve_user(obj, info, id):
if not id:
raise GraphQLError("User ID is required")
if not is_valid_id(id):
raise GraphQLError(
f"Invalid user ID: {id}",
extensions={'code': 'INVALID_INPUT', 'field': 'id'}
)
user = find_user(id)
if not user:
raise GraphQLError(
f"User not found: {id}",
extensions={'code': 'NOT_FOUND', 'resourceType': 'User', 'id': id}
)
return user
# Handle authorization errors
def resolve_sensitive_field(obj, info):
if not info.context.get('user'):
raise GraphQLError(
"Authentication required",
extensions={'code': 'UNAUTHENTICATED'}
)
if not has_permission(info.context.user, 'read_sensitive_data'):
raise GraphQLError(
"Insufficient permissions",
extensions={'code': 'FORBIDDEN', 'permission': 'read_sensitive_data'}
)
return obj.sensitive_data
# Wrap external service errors
def resolve_external_data(obj, info):
try:
return external_api.get_data(obj.id)
except ExternalServiceError as e:
raise GraphQLError(
"External service unavailable",
original_error=e,
extensions={'code': 'SERVICE_UNAVAILABLE', 'service': 'external_api'}
)
except ValidationError as e:
raise GraphQLError(
f"Data validation failed: {e.message}",
original_error=e,
extensions={'code': 'DATA_VALIDATION_ERROR'}
)Handle multiple errors in execution results.
from graphql import ExecutionResult, GraphQLError
def create_execution_result_with_errors():
errors = [
GraphQLError("First error", path=['field1']),
GraphQLError("Second error", path=['field2']),
]
return ExecutionResult(
data={'field1': None, 'field2': None, 'field3': 'success'},
errors=errors
)
# Error filtering and processing
def process_execution_result(result):
if result.errors:
# Categorize errors
validation_errors = []
auth_errors = []
system_errors = []
for error in result.errors:
code = error.extensions.get('code') if error.extensions else None
if code in ['INVALID_INPUT', 'DATA_VALIDATION_ERROR']:
validation_errors.append(error)
elif code in ['UNAUTHENTICATED', 'FORBIDDEN']:
auth_errors.append(error)
else:
system_errors.append(error)
# Handle different error types appropriately
if auth_errors:
# Return 401/403 HTTP status
pass
elif validation_errors and not system_errors:
# Return 400 HTTP status
pass
elif system_errors:
# Log and return 500 HTTP status
passCreate domain-specific error classes for better error handling.
from graphql import GraphQLError
class ValidationError(GraphQLError):
def __init__(self, message, field=None, value=None):
super().__init__(
message,
extensions={
'code': 'VALIDATION_ERROR',
'field': field,
'value': value
}
)
class AuthenticationError(GraphQLError):
def __init__(self, message="Authentication required"):
super().__init__(
message,
extensions={'code': 'UNAUTHENTICATED'}
)
class AuthorizationError(GraphQLError):
def __init__(self, message="Insufficient permissions", permission=None):
super().__init__(
message,
extensions={
'code': 'FORBIDDEN',
'permission': permission
}
)
class NotFoundError(GraphQLError):
def __init__(self, resource_type, resource_id):
super().__init__(
f"{resource_type} not found: {resource_id}",
extensions={
'code': 'NOT_FOUND',
'resourceType': resource_type,
'id': resource_id
}
)
# Usage in resolvers
def resolve_user(obj, info, id):
if not info.context.get('user'):
raise AuthenticationError()
if not is_valid_id(id):
raise ValidationError("Invalid ID format", field='id', value=id)
user = find_user(id)
if not user:
raise NotFoundError('User', id)
return userDebug and analyze GraphQL errors with detailed information.
from graphql import GraphQLError
import traceback
import logging
def debug_graphql_error(error: GraphQLError):
print(f"GraphQL Error: {error.message}")
if error.locations:
for loc in error.locations:
print(f" Location: line {loc.line}, column {loc.column}")
if error.path:
print(f" Path: {' -> '.join(map(str, error.path))}")
if error.extensions:
print(f" Extensions: {error.extensions}")
if error.original_error:
print(f" Original error: {error.original_error}")
print(f" Traceback:")
traceback.print_exception(
type(error.original_error),
error.original_error,
error.original_error.__traceback__
)
# Logging middleware
class ErrorLoggingMiddleware:
def __init__(self, logger=None):
self.logger = logger or logging.getLogger(__name__)
def resolve(self, next_resolver, root, info, **args):
try:
result = next_resolver(root, info, **args)
return result
except GraphQLError as e:
# Log GraphQL errors with context
self.logger.error(
f"GraphQL error in {info.parent_type.name}.{info.field_name}: {e.message}",
extra={
'field_path': info.path,
'operation': info.operation.operation.value,
'variables': info.variable_values,
'extensions': e.extensions
}
)
raise
except Exception as e:
# Log and convert unexpected errors
self.logger.exception(
f"Unexpected error in {info.parent_type.name}.{info.field_name}",
extra={'field_path': info.path}
)
raise located_error(e, info.field_nodes, info.path)# Import required types
from typing import Any, Dict, List, Optional, Union, Sequence
from graphql.language import Node, Source, SourceLocation
from graphql.error import GraphQLError, GraphQLSyntaxError
# Error format types
GraphQLFormattedError = Dict[str, Any]
GraphQLErrorExtensions = Dict[str, Any]
# Core error classes
GraphQLError = class GraphQLError(Exception)
GraphQLSyntaxError = class GraphQLSyntaxError(GraphQLError)
# Error creation function
def located_error(
original_error: Exception,
nodes: Optional[Union[Node, Sequence[Node]]] = None,
path: Optional[Sequence[Union[str, int]]] = None,
) -> GraphQLError
# Location information
class SourceLocation:
line: int
column: int
# Execution result with errors
class ExecutionResult:
data: Optional[Dict[str, Any]]
errors: Optional[List[GraphQLError]]
extensions: Optional[Dict[str, Any]]Install with Tessl CLI
npx tessl i tessl/pypi-graphql-core