or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

error-handling.mdindex.mdplugins.mdserver-setup.mdtypes.md
tile.json

error-handling.mddocs/

Error Handling

Specialized GraphQL error classes with proper formatting and extensions. Apollo Server provides structured error handling with specific error codes for common scenarios.

Capabilities

Base Error Class

ApolloError

Base GraphQL error class that all other Apollo errors extend. Provides structured error information with extensions.

/**
 * Base Apollo GraphQL error class
 * Extends standard Error with GraphQL-specific extensions
 */
class ApolloError extends Error {
  /**
   * Create a new Apollo error
   * @param message - Human-readable error message
   * @param code - Error code for client identification
   * @param extensions - Additional error metadata
   */
  constructor(
    message: string,
    code?: string,
    extensions?: Record<string, any>
  );
  
  /** Error code for programmatic handling */
  code?: string;
  
  /** Additional error information */
  extensions: Record<string, any>;
}

Usage Examples:

import { ApolloError } from 'apollo-server';

// Basic error
throw new ApolloError('Something went wrong', 'INTERNAL_ERROR');

// Error with extensions
throw new ApolloError(
  'Rate limit exceeded',
  'RATE_LIMITED',
  {
    retryAfter: 60,
    limit: 100,
    remaining: 0,
  }
);

// In resolvers
const resolvers = {
  Query: {
    sensitiveData: (parent, args, context) => {
      if (!context.user) {
        throw new ApolloError(
          'Authentication required',
          'UNAUTHENTICATED',
          { timestamp: new Date().toISOString() }
        );
      }
      return getSensitiveData();
    },
  },
};

Authentication Errors

AuthenticationError

Error for authentication failures when user credentials are missing or invalid.

/**
 * Authentication error - user is not authenticated
 * Automatically sets code to 'UNAUTHENTICATED'
 */
class AuthenticationError extends ApolloError {
  /**
   * Create an authentication error
   * @param message - Error message describing authentication failure
   */
  constructor(message: string);
}

Usage Examples:

import { AuthenticationError } from 'apollo-server';

// In context function
const server = new ApolloServer({
  typeDefs,
  resolvers,
  context: ({ req }) => {
    const token = req.headers.authorization;
    if (!token) {
      throw new AuthenticationError('Authorization token required');
    }
    
    const user = validateToken(token);
    if (!user) {
      throw new AuthenticationError('Invalid or expired token');
    }
    
    return { user };
  },
});

// In resolvers
const resolvers = {
  Mutation: {
    updateProfile: (parent, args, context) => {
      if (!context.user) {
        throw new AuthenticationError('Must be logged in to update profile');
      }
      return updateUserProfile(context.user.id, args.input);
    },
  },
};

Authorization Errors

ForbiddenError

Error for authorization failures when user is authenticated but lacks required permissions.

/**
 * Authorization error - user is authenticated but not authorized
 * Automatically sets code to 'FORBIDDEN'
 */
class ForbiddenError extends ApolloError {
  /**
   * Create a forbidden error
   * @param message - Error message describing authorization failure
   */
  constructor(message: string);
}

Usage Examples:

import { ForbiddenError } from 'apollo-server';

const resolvers = {
  Mutation: {
    deleteUser: (parent, args, context) => {
      if (!context.user) {
        throw new AuthenticationError('Authentication required');
      }
      
      if (context.user.role !== 'admin') {
        throw new ForbiddenError('Admin privileges required');
      }
      
      return deleteUser(args.id);
    },
  },
  Query: {
    adminStats: (parent, args, context) => {
      if (!context.user?.isAdmin) {
        throw new ForbiddenError('Access denied: admin only');
      }
      return getAdminStatistics();
    },
  },
};

Input Validation Errors

UserInputError

Error for invalid user input, such as validation failures or malformed data.

/**
 * User input error - invalid or malformed input data
 * Automatically sets code to 'BAD_USER_INPUT'
 */
class UserInputError extends ApolloError {
  /**
   * Create a user input error
   * @param message - Error message describing input problem
   * @param properties - Additional error properties (often validation details)
   */
  constructor(message: string, properties?: Record<string, any>);
}

Usage Examples:

import { UserInputError } from 'apollo-server';

const resolvers = {
  Mutation: {
    createUser: (parent, args, context) => {
      const { input } = args;
      
      // Email validation
      if (!isValidEmail(input.email)) {
        throw new UserInputError('Invalid email format', {
          field: 'email',
          value: input.email,
        });
      }
      
      // Password strength validation
      if (input.password.length < 8) {
        throw new UserInputError('Password must be at least 8 characters');
      }
      
      // Multiple validation errors
      const errors = validateUserInput(input);
      if (errors.length > 0) {
        throw new UserInputError('Invalid input data', {
          validationErrors: errors,
        });
      }
      
      return createUser(input);
    },
  },
};

GraphQL Syntax and Validation Errors

SyntaxError

Error for GraphQL syntax parsing failures.

/**
 * GraphQL syntax error - malformed GraphQL document
 * Automatically sets code to 'GRAPHQL_PARSE_FAILED'
 */
class SyntaxError extends ApolloError {
  /**
   * Create a syntax error
   * @param message - Error message describing syntax problem
   */
  constructor(message: string);
}

ValidationError

Error for GraphQL validation rule failures.

/**
 * GraphQL validation error - document violates GraphQL validation rules
 * Automatically sets code to 'GRAPHQL_VALIDATION_FAILED'
 */
class ValidationError extends ApolloError {
  /**
   * Create a validation error
   * @param message - Error message describing validation failure
   */
  constructor(message: string);
}

Error Utility Functions

toApolloError

Converts standard JavaScript errors to Apollo errors with proper extensions.

/**
 * Convert a standard Error to an Apollo error with extensions
 * @param error - Standard JavaScript error to convert
 * @param code - Optional error code to assign
 * @returns Error with Apollo extensions
 */
function toApolloError(
  error: Error,
  code?: string
): Error & { extensions: Record<string, any> };

Usage Examples:

import { toApolloError } from 'apollo-server';

const resolvers = {
  Query: {
    userData: async (parent, args, context) => {
      try {
        return await fetchUserData(args.id);
      } catch (error) {
        // Convert database error to Apollo error
        throw toApolloError(error, 'DATABASE_ERROR');
      }
    },
  },
  Mutation: {
    processPayment: async (parent, args, context) => {
      try {
        return await processPayment(args.input);
      } catch (error) {
        if (error.code === 'CARD_DECLINED') {
          throw toApolloError(error, 'PAYMENT_FAILED');
        }
        throw toApolloError(error, 'PAYMENT_ERROR');
      }
    },
  },
};

Error Formatting and Handling

Custom error formatting and global error handling configuration.

// Global error formatting
const server = new ApolloServer({
  typeDefs,
  resolvers,
  formatError: (error) => {
    // Log errors for debugging
    console.error('GraphQL Error:', error);
    
    // Remove sensitive information in production
    if (process.env.NODE_ENV === 'production') {
      delete error.extensions?.exception?.stacktrace;
    }
    
    // Add request ID for tracking
    return {
      ...error,
      extensions: {
        ...error.extensions,
        requestId: generateRequestId(),
      },
    };
  },
});

// Error handling in plugins
const errorHandlingPlugin = {
  requestDidStart() {
    return {
      didEncounterErrors(requestContext) {
        // Custom error processing
        for (const error of requestContext.errors) {
          if (error.originalError?.code === 'DATABASE_CONNECTION_FAILED') {
            // Log critical database errors
            logger.critical('Database connection failed', { error });
          }
        }
      },
    };
  },
};

Error Response Format

Apollo Server formats errors according to the GraphQL specification:

{
  "errors": [
    {
      "message": "Authentication required",
      "locations": [{ "line": 3, "column": 5 }],
      "path": ["user", "profile"],
      "extensions": {
        "code": "UNAUTHENTICATED",
        "timestamp": "2023-12-01T10:30:00.000Z"
      }
    }
  ],
  "data": null
}

Best Practices for Error Handling

// 1. Use specific error types
const resolvers = {
  Query: {
    user: (parent, args, context) => {
      // Authentication check
      if (!context.user) {
        throw new AuthenticationError('Please log in');
      }
      
      // Authorization check
      if (context.user.id !== args.id && !context.user.isAdmin) {
        throw new ForbiddenError('Cannot access other user data');
      }
      
      // Input validation
      if (!isValidUserId(args.id)) {
        throw new UserInputError('Invalid user ID format');
      }
      
      return getUserById(args.id);
    },
  },
};

// 2. Provide helpful error messages
throw new UserInputError('Email address is required', {
  field: 'email',
  received: args.input.email,
});

// 3. Include relevant context in extensions
throw new ApolloError('Rate limit exceeded', 'RATE_LIMITED', {
  limit: 100,
  window: '1h',
  retryAfter: 3600,
  userId: context.user.id,
});

// 4. Handle errors at appropriate levels
const server = new ApolloServer({
  typeDefs,
  resolvers,
  plugins: [
    {
      requestDidStart() {
        return {
          willSendResponse(requestContext) {
            // Add correlation IDs to all responses
            if (requestContext.response.http) {
              requestContext.response.http.headers.set(
                'x-correlation-id',
                requestContext.request.http?.headers.get('x-correlation-id') || generateId()
              );
            }
          },
        };
      },
    },
  ],
});