Error Handling

Error types and handling patterns for Gatekeeper middleware

Gatekeeper provides typed error classes for consistent error handling across your application.

Error Classes

AuthError

Thrown when authentication fails.

import { AuthError } from '@mira.network/gatekeeper';

// Thrown when:
// - Authorization header is missing
// - Token format is invalid
// - Token prefix doesn't match service
// - API key validation fails

HTTP Status: 401 Unauthorized

Response Format:

{
  "error": "Unauthorized",
  "message": "Authorization header required"
}

RateLimitError

Thrown when rate limit is exceeded.

import { RateLimitError } from '@mira.network/gatekeeper';

// Properties:
// - type: 'minute' | 'day' - Which limit was exceeded
// - resetAt: number - Unix timestamp when limit resets
// - retryAfter: number - Seconds until limit resets

HTTP Status: 429 Too Many Requests

Response Format:

{
  "error": "Rate Limit Exceeded",
  "message": "Per-minute rate limit exceeded",
  "resetAt": 1699999999
}

Headers:

Retry-After: 45

InsufficientBalanceError

Thrown when app has insufficient balance.

import { InsufficientBalanceError } from '@mira.network/gatekeeper';

// Properties:
// - balance: number - Current balance

HTTP Status: 402 Payment Required

Response Format:

{
  "error": "Payment Required",
  "message": "Insufficient balance",
  "balance": 0
}

Error Handling Pattern

Handle all Gatekeeper errors in your Hono app's error handler:

import {
  AuthError,
  RateLimitError,
  InsufficientBalanceError,
} from '@mira.network/gatekeeper';

app.onError((err, c) => {
  if (err instanceof AuthError) {
    return c.json(
      { error: 'Unauthorized', message: err.message },
      401
    );
  }

  if (err instanceof RateLimitError) {
    c.header('Retry-After', err.retryAfter.toString());
    return c.json(
      {
        error: 'Rate Limit Exceeded',
        message: err.message,
        resetAt: err.resetAt,
      },
      429
    );
  }

  if (err instanceof InsufficientBalanceError) {
    return c.json(
      {
        error: 'Payment Required',
        message: 'Insufficient balance',
        balance: err.balance,
      },
      402
    );
  }

  // Handle other errors
  console.error(err);
  return c.json({ error: 'Internal Server Error' }, 500);
});

Type Guards

You can also use instanceof checks in try-catch blocks:

app.post('/api/endpoint', async (c) => {
  try {
    // Your handler logic
  } catch (err) {
    if (err instanceof AuthError) {
      // Handle auth error
    }
    throw err; // Re-throw to global error handler
  }
});

Error Properties Reference

Error ClassProperties
AuthErrormessage: string
RateLimitErrortype: 'minute' | 'day', resetAt: number, retryAfter: number
InsufficientBalanceErrorbalance: number