> ## Documentation Index
> Fetch the complete documentation index at: https://docs.agentfront.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Errors Overview

> FrontMCP provides a comprehensive error hierarchy with MCP-compliant error codes for proper JSON-RPC error responses.

## MCP Error Codes

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
export const MCP_ERROR_CODES = {
  UNAUTHORIZED: -32001,          // Missing credentials
  RESOURCE_NOT_FOUND: -32002,    // Resource not found
  FORBIDDEN: -32003,             // Invalid/insufficient credentials
  INVALID_REQUEST: -32600,       // Invalid request
  METHOD_NOT_FOUND: -32601,      // Method not found
  INVALID_PARAMS: -32602,        // Invalid parameters
  INTERNAL_ERROR: -32603,        // Internal server error
  PARSE_ERROR: -32700,           // Parse error
} as const;
```

## Error Hierarchy

```
McpError (abstract)
├── PublicMcpError (safe to expose to clients)
│   ├── ToolNotFoundError
│   ├── ResourceNotFoundError
│   ├── InvalidInputError
│   ├── UnauthorizedError
│   ├── RateLimitError
│   └── ...
│
└── InternalMcpError (hide details from clients)
    ├── ToolExecutionError
    ├── ResourceReadError
    ├── InvalidOutputError
    └── ...
```

## Base Error Classes

### McpError (Abstract)

Base class for all MCP-related errors.

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
abstract class McpError extends Error {
  readonly errorId: string;           // Unique ID for tracking
  abstract isPublic: boolean;         // Expose details to clients?
  abstract statusCode: number;        // HTTP status code
  abstract code: string;              // Error code

  abstract getPublicMessage(): string;
  getInternalMessage(): string;
  toMcpError(isDevelopment?: boolean): McpErrorResponse;
}
```

### PublicMcpError

Errors safe to expose to clients (validation errors, not found, etc.).

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
class PublicMcpError extends McpError {
  readonly isPublic = true;
  /** Optional `WWW-Authenticate` response header value (e.g. `'Bearer'`) for 401 challenges. */
  readonly wwwAuthenticate?: string;

  constructor(message: string, code?: string, statusCode?: number, wwwAuthenticate?: string);
}
```

### InternalMcpError

Errors that should NOT expose details (server errors, unexpected failures).

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
class InternalMcpError extends McpError {
  readonly isPublic = false;
  readonly statusCode = 500;

  getPublicMessage(): string {
    return `Internal FrontMCP error. Please contact support with error ID: ${this.errorId}`;
  }
}
```

## Error Categories

<CardGroup cols={2}>
  <Card title="Tool & Prompt Errors" icon="wrench" href="/frontmcp/sdk-reference/errors/tool-errors">
    ToolNotFoundError, ToolExecutionError, PromptNotFoundError, PromptExecutionError
  </Card>

  <Card title="Resource Errors" icon="file" href="/frontmcp/sdk-reference/errors/resource-errors">
    ResourceNotFoundError, ResourceReadError, InvalidResourceUriError
  </Card>

  <Card title="Validation Errors" icon="check" href="/frontmcp/sdk-reference/errors/validation-errors">
    InvalidInputError, InvalidOutputError, InvalidMethodError, MissingPromptArgumentError
  </Card>

  <Card title="Auth Errors" icon="lock" href="/frontmcp/sdk-reference/errors/auth-errors">
    UnauthorizedError, AuthConfigurationError, SessionMissingError, AuthorizationRequiredError
  </Card>

  <Card title="Agent Errors" icon="robot" href="/frontmcp/sdk-reference/errors/agent-errors">
    AgentNotFoundError, AgentExecutionError, AgentLoopExceededError, AgentTimeoutError
  </Card>

  <Card title="Rate Limit Errors" icon="gauge" href="/frontmcp/sdk-reference/errors/rate-limit-errors">
    RateLimitError, QuotaExceededError
  </Card>

  <Card title="Transport Errors" icon="plug" href="/frontmcp/sdk-reference/errors/transport-errors">
    TransportNotConnectedError, UnsupportedContentTypeError
  </Card>

  <Card title="Remote Errors" icon="tower-broadcast" href="/frontmcp/sdk-reference/errors/remote-errors">
    RemoteConnectionError, RemoteTimeoutError, RemoteToolNotFoundError
  </Card>

  <Card title="Elicitation Errors" icon="comment-dots" href="/frontmcp/sdk-reference/errors/elicitation-errors">
    ElicitationNotSupportedError, ElicitationTimeoutError, ElicitationFallbackRequired
  </Card>

  <Card title="Provider Errors" icon="cubes" href="/frontmcp/sdk-reference/errors/provider-errors">
    ProviderNotRegisteredError, DependencyCycleError, ProviderConstructionError
  </Card>

  <Card title="Registry Errors" icon="database" href="/frontmcp/sdk-reference/errors/registry-errors">
    RegistryDefinitionNotFoundError, FlowNotRegisteredError, EntryValidationError
  </Card>

  <Card title="Decorator Errors" icon="at" href="/frontmcp/sdk-reference/errors/decorator-errors">
    InvalidDecoratorMetadataError, HookTargetNotDefinedError
  </Card>

  <Card title="Normalization Errors" icon="filter" href="/frontmcp/sdk-reference/errors/normalization-errors">
    MissingProvideError, InvalidUseClassError, InvalidEntityError
  </Card>

  <Card title="SDK Errors" icon="gear" href="/frontmcp/sdk-reference/errors/sdk-errors">
    FlowExitedWithoutOutputError, ServerNotFoundError, ConfigNotFoundError
  </Card>

  <Card title="Auth Internal Errors" icon="shield-halved" href="/frontmcp/sdk-reference/errors/auth-internal-errors">
    EncryptionContextNotSetError, VaultLoadError, TokenLeakDetectedError
  </Card>

  <Card title="ESM Errors" icon="box-open" href="/frontmcp/sdk-reference/errors/esm-errors">
    EsmPackageLoadError, EsmVersionResolutionError, EsmManifestInvalidError, EsmCacheError, EsmRegistryAuthError, EsmInvalidSpecifierError
  </Card>
</CardGroup>

## Usage Patterns

### Throwing Errors

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
import { ToolNotFoundError, InvalidInputError } from '@frontmcp/sdk';

@Tool({ name: 'my_tool', inputSchema: { id: z.string() } })
class MyTool extends ToolContext {
  async execute(input: { id: string }) {
    if (!input.id) {
      throw new InvalidInputError('ID is required');
    }

    const item = await this.get(Service).find(input.id);
    if (!item) {
      throw new ToolNotFoundError('my_tool');
    }

    return item;
  }
}
```

### Using fail()

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
@Tool({ name: 'my_tool', inputSchema: {} })
class MyTool extends ToolContext {
  async execute(input) {
    if (!valid) {
      this.fail(new InvalidInputError('Validation failed'));
      // Never reaches here - fail() throws
    }
  }
}
```

### Error with Details

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
throw new InvalidInputError('Validation failed', {
  field: 'email',
  reason: 'Invalid format',
});
```

### Custom toJsonRpcError

Some errors override `toJsonRpcError()` for custom data:

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
class ResourceNotFoundError extends PublicMcpError {
  toJsonRpcError() {
    return {
      code: MCP_ERROR_CODES.RESOURCE_NOT_FOUND,
      message: this.getPublicMessage(),
      data: { uri: this.uri },
    };
  }
}
```

## How Entry Errors Reach the Client

The same rules apply to tools, resources and prompts, whether the error is thrown or passed to `this.fail()`:

* **Public errors pass through.** A `PublicMcpError` (or subclass, such as `InvalidInputError` or `ResourceNotFoundError`) and an authorities refusal reach the client with their own message and code.
* **Anything else is wrapped** in `ToolExecutionError`, `ResourceReadError` or `PromptExecutionError`. In production the client sees only the generic message with the `errorId`.
* **Every failure is logged once**, with the same `errorId` the client sees and the error code. For an error the SDK wrapped, the logged message includes the original error's message and stack in every environment; the stack of the reported error itself is logged in development only.

Two predicates exported from `@frontmcp/sdk` apply the same rules in code that catches errors around entries, such as hooks:

* `isClientFacingError(error: unknown): boolean` is true for a public error (`PublicMcpError` or a subclass) and for an authorities refusal (`AuthorityDeniedError`). The flows pass these on unwrapped.
* `isMrtrSignal(error: unknown): error is InputRequiredSignal | MissingClientCapabilityError` is true for the two signals the 2026-07-28 dispatcher answers itself: an `input_required` result and a `-32021` error. Rethrow them instead of reporting them as failures.

`tools/call` answers with a result that has `isError: true` and `_meta.code` / `_meta.errorId`. `resources/read` and `prompts/get` answer with a JSON-RPC error. Its code comes from the error's `toJsonRpcError()` when it has one; otherwise it depends on `statusCode`:

| `statusCode` | JSON-RPC code |
| - | - |
| `401` | `-32001` |
| `403` | `-32003` |
| other `4xx` | `-32602` |
| `5xx` or internal | `-32603` |

`data` carries the `errorId` and `code`. An error with its own `toJsonRpcError()` keeps its `data`, with the `errorId` added. Under protocol 2026-07-28, `-32002` (resource not found) is sent as `-32602`.

## Error Properties

| Property | Type | Description |
| - | - | - |
| `errorId` | `string` | Unique ID for tracking (auto-generated) |
| `isPublic` | `boolean` | Whether to expose message to clients |
| `statusCode` | `number` | HTTP status code equivalent |
| `wwwAuthenticate` | `string?` | Optional `WWW-Authenticate` header value (e.g. `'Bearer'`) for 401 challenges |
| `code` | `string` | Error code for categorization |
| `mcpErrorCode` | `number` | JSON-RPC error code (optional) |

## Best Practices

### Use Specific Error Classes

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
// Good
throw new ToolNotFoundError('my_tool');
throw new InvalidInputError('Email is required');

// Avoid
throw new Error('Tool not found');
```

### Preserve Original Errors

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
try {
  await externalService.call();
} catch (error) {
  throw new ToolExecutionError('my_tool', error);
}
```

### Don't Expose Internal Details

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
// InternalMcpError hides message from clients
throw new InternalMcpError('Database connection failed: timeout after 30s');
// Client sees: "Internal FrontMCP error. Please contact support with error ID: err_3f9a1c2b7d4e8f06"
```

A generated error ID is `err_` followed by 16 hex characters (8 random bytes).

### Use Error IDs for Tracking

FrontMCP already logs each failed tool call, resource read and prompt with its `errorId`. Log it yourself when you handle an error in your own code:

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
try {
  // operation
} catch (error) {
  if (error instanceof McpError) {
    logger.error('Operation failed', {
      errorId: error.errorId,
      code: error.code,
    });
  }
  throw error;
}
```

## Import

```typescript theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
import {
  MCP_ERROR_CODES,
  McpError,
  PublicMcpError,
  InternalMcpError,
  ToolNotFoundError,
  ToolExecutionError,
  ResourceNotFoundError,
  ResourceReadError,
  InvalidInputError,
  InvalidOutputError,
  UnauthorizedError,
  RateLimitError,
  // ... more
} from '@frontmcp/sdk';
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.