or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

core-execution.mderror-handling.mdexecution-engine.mdindex.mdlanguage-processing.mdschema-utilities.mdtype-system.mdvalidation-system.md
tile.json

error-handling.mddocs/

Error Handling

GraphQL.js provides comprehensive error handling with source location tracking, path information, and response formatting capabilities.

Capabilities

GraphQL Error Class

The main error class for GraphQL operations with rich context information.

/**
 * GraphQL error with location and context information
 */
class GraphQLError extends Error {
  constructor(message: string, options?: GraphQLErrorOptions);
  
  /** Error message */
  readonly message: string;
  
  /** Source locations where error occurred */
  readonly locations?: ReadonlyArray<SourceLocation>;
  
  /** Response path where error occurred */
  readonly path?: ReadonlyArray<string | number>;
  
  /** Source document */
  readonly source?: Source;
  
  /** Character positions in source */
  readonly positions?: ReadonlyArray<number>;
  
  /** Original error that was wrapped */
  readonly originalError?: Error;
  
  /** Additional error data */
  readonly extensions?: GraphQLErrorExtensions;
  
  /** AST nodes related to error */
  readonly nodes?: ReadonlyArray<ASTNode>;
  
  /** Convert error to JSON format for responses */
  toJSON(): GraphQLFormattedError;
}

interface GraphQLErrorOptions {
  /** AST nodes where error occurred */
  nodes?: ReadonlyArray<ASTNode>;
  /** Source document */
  source?: Source;
  /** Character positions in source */
  positions?: ReadonlyArray<number>;
  /** Response path */
  path?: ReadonlyArray<string | number>;
  /** Original error to wrap */
  originalError?: Error;
  /** Additional error data */
  extensions?: GraphQLErrorExtensions;
}

interface GraphQLErrorExtensions {
  [key: string]: unknown;
}

Usage Examples:

import { GraphQLError } from "graphql";

// Basic error
const error = new GraphQLError("Something went wrong");

// Error with location information
const errorWithLocation = new GraphQLError(
  "Invalid field selection",
  {
    nodes: [fieldNode],
    path: ["user", "invalidField"]
  }
);

// Error with extensions
const errorWithExtensions = new GraphQLError(
  "Authentication required",
  {
    extensions: {
      code: "UNAUTHENTICATED",
      statusCode: 401,
      timestamp: new Date().toISOString()
    }
  }
);

// Error wrapping original error
const wrappedError = new GraphQLError(
  "Database connection failed",
  {
    originalError: originalDbError,
    extensions: { code: "DATABASE_ERROR" }
  }
);

Error Creation Functions

Utility functions for creating specific types of GraphQL errors.

/**
 * Create a syntax error for GraphQL parsing
 * @param source - Source document
 * @param position - Character position of error
 * @param description - Error description
 * @returns GraphQL syntax error
 */
function syntaxError(
  source: Source,
  position: number,
  description: string
): GraphQLError;

/**
 * Wrap an error with GraphQL location information
 * @param originalError - Original error to wrap
 * @param nodes - AST nodes where error occurred
 * @param path - Response path where error occurred
 * @returns GraphQL error with location info
 */
function locatedError(
  originalError: Error | GraphQLError,
  nodes?: ReadonlyArray<ASTNode>,
  path?: ReadonlyArray<string | number>
): GraphQLError;

Usage Examples:

import { syntaxError, locatedError, Source } from "graphql";

// Create syntax error during parsing
const source = new Source("{ user { name }"); // missing closing brace
const parseError = syntaxError(source, 13, "Expected '}'");

// Wrap resolver error with location
const resolverError = new Error("User not found");
const locatedResolverError = locatedError(
  resolverError,
  [fieldNode],
  ["user"]
);

// Use in field resolver
const userResolver = async (parent, args, context, info) => {
  try {
    return await fetchUser(args.id);
  } catch (error) {
    throw locatedError(error, info.fieldNodes, info.path);
  }
};

Error Formatting

Functions for formatting errors for different output contexts.

/**
 * Format GraphQL error for JSON response
 * @param error - GraphQL error to format
 * @returns Formatted error object
 */
function formatError(error: GraphQLError): GraphQLFormattedError;

/**
 * Print GraphQL error with source context
 * @param error - GraphQL error to print
 * @returns Human-readable error string with source context
 */
function printError(error: GraphQLError): string;

interface GraphQLFormattedError {
  /** Error message */
  readonly message: string;
  /** Source locations */
  readonly locations?: ReadonlyArray<SourceLocation>;
  /** Response path */
  readonly path?: ReadonlyArray<string | number>;
  /** Additional error data */
  readonly extensions?: GraphQLFormattedErrorExtensions;
}

interface GraphQLFormattedErrorExtensions {
  [key: string]: unknown;
}

interface SourceLocation {
  readonly line: number;
  readonly column: number;
}

Usage Examples:

import { formatError, printError, GraphQLError } from "graphql";

const error = new GraphQLError(
  "Cannot query field 'invalidField' on type 'User'",
  {
    nodes: [fieldNode],
    path: ["user", "invalidField"],
    extensions: { code: "INVALID_FIELD" }
  }
);

// Format for JSON response
const formattedError = formatError(error);
console.log(JSON.stringify(formattedError, null, 2));
/*
{
  "message": "Cannot query field 'invalidField' on type 'User'",
  "locations": [{ "line": 3, "column": 5 }],
  "path": ["user", "invalidField"],
  "extensions": { "code": "INVALID_FIELD" }
}
*/

// Print with source context for debugging
const errorString = printError(error);
console.log(errorString);
/*
Cannot query field 'invalidField' on type 'User'

GraphQL request:3:5
2 |   user {
3 |     invalidField
  |     ^
4 |   }
*/

// Format multiple errors from execution result
const result = await execute({ schema, document, rootValue });
if (result.errors) {
  const formattedErrors = result.errors.map(formatError);
  return { data: result.data, errors: formattedErrors };
}

Error Handling in Resolvers

Best practices for error handling in field resolvers.

Usage Examples:

import { GraphQLError, locatedError } from "graphql";

// Field resolver with proper error handling
const userResolver = async (parent, args, context, info) => {
  try {
    // Check authentication
    if (!context.user) {
      throw new GraphQLError("Authentication required", {
        extensions: { code: "UNAUTHENTICATED" }
      });
    }
    
    // Check authorization
    if (!context.user.canAccessUser(args.id)) {
      throw new GraphQLError("Insufficient permissions", {
        extensions: { code: "FORBIDDEN" }
      });
    }
    
    // Fetch user data
    const user = await context.dataSources.users.findById(args.id);
    
    if (!user) {
      throw new GraphQLError(`User not found: ${args.id}`, {
        extensions: { code: "NOT_FOUND" }
      });
    }
    
    return user;
    
  } catch (error) {
    // Wrap non-GraphQL errors
    if (!(error instanceof GraphQLError)) {
      throw locatedError(error, info.fieldNodes, info.path);
    }
    throw error;
  }
};

// Custom error classes for different scenarios
class AuthenticationError extends GraphQLError {
  constructor(message = "Authentication required") {
    super(message, {
      extensions: { code: "UNAUTHENTICATED" }
    });
  }
}

class ValidationError extends GraphQLError {
  constructor(message: string, field?: string) {
    super(message, {
      extensions: { 
        code: "VALIDATION_ERROR",
        field 
      }
    });
  }
}

// Usage in resolvers
const createUserResolver = async (parent, args, context) => {
  if (!context.user) {
    throw new AuthenticationError();
  }
  
  if (!args.input.email) {
    throw new ValidationError("Email is required", "email");
  }
  
  if (!isValidEmail(args.input.email)) {
    throw new ValidationError("Invalid email format", "email");
  }
  
  try {
    return await context.dataSources.users.create(args.input);
  } catch (dbError) {
    if (dbError.code === "DUPLICATE_EMAIL") {
      throw new ValidationError("Email already exists", "email");
    }
    throw new GraphQLError("Failed to create user", {
      originalError: dbError,
      extensions: { code: "DATABASE_ERROR" }
    });
  }
};

Error Handling in Execution

How errors are handled during GraphQL execution.

Usage Examples:

import { execute, formatError } from "graphql";

// Execute with error handling
const executeWithErrorHandling = async (args) => {
  try {
    const result = await execute(args);
    
    // Handle execution errors
    if (result.errors && result.errors.length > 0) {
      // Log errors for debugging
      result.errors.forEach(error => {
        console.error("GraphQL Error:", printError(error));
        
        // Log original error if available
        if (error.originalError) {
          console.error("Original Error:", error.originalError);
        }
      });
      
      // Format errors for response
      return {
        data: result.data,
        errors: result.errors.map(formatError)
      };
    }
    
    return { data: result.data };
    
  } catch (error) {
    // Handle unexpected errors
    console.error("Unexpected execution error:", error);
    
    return {
      data: null,
      errors: [formatError(new GraphQLError("Internal server error"))]
    };
  }
};

// Custom error formatter
const customFormatError = (error: GraphQLError) => {
  // Don't expose internal errors to clients
  if (error.originalError && error.extensions?.code !== "VALIDATION_ERROR") {
    return formatError(new GraphQLError("Internal server error"));
  }
  
  // Format validation errors with more detail
  if (error.extensions?.code === "VALIDATION_ERROR") {
    return {
      ...formatError(error),
      extensions: {
        ...error.extensions,
        timestamp: new Date().toISOString()
      }
    };
  }
  
  return formatError(error);
};

// Use custom formatter
const result = await execute(args);
if (result.errors) {
  return {
    data: result.data,
    errors: result.errors.map(customFormatError)
  };
}

Error Extensions and Codes

Common patterns for error extensions and error codes.

// Common error extension patterns
interface ErrorExtensions {
  /** Error code for programmatic handling */
  code?: string;
  /** HTTP status code */
  statusCode?: number;
  /** Timestamp when error occurred */
  timestamp?: string;
  /** Additional context data */
  context?: Record<string, unknown>;
  /** Stack trace (development only) */
  stacktrace?: string[];
}

// Standard error codes
enum ErrorCode {
  GRAPHQL_PARSE_FAILED = "GRAPHQL_PARSE_FAILED",
  GRAPHQL_VALIDATION_FAILED = "GRAPHQL_VALIDATION_FAILED", 
  BAD_USER_INPUT = "BAD_USER_INPUT",
  UNAUTHENTICATED = "UNAUTHENTICATED",
  FORBIDDEN = "FORBIDDEN",
  NOT_FOUND = "NOT_FOUND",
  INTERNAL_ERROR = "INTERNAL_ERROR"
}

Usage Examples:

// Structured error with comprehensive extensions
const createStructuredError = (
  message: string,
  code: string,
  statusCode?: number,
  additionalData?: Record<string, unknown>
) => {
  return new GraphQLError(message, {
    extensions: {
      code,
      statusCode,
      timestamp: new Date().toISOString(),
      ...additionalData
    }
  });
};

// Usage examples
const authError = createStructuredError(
  "Authentication required",
  "UNAUTHENTICATED",
  401
);

const validationError = createStructuredError(
  "Invalid input data",
  "BAD_USER_INPUT",
  400,
  { 
    field: "email",
    rejectedValue: "invalid-email" 
  }
);