Vue Storefront is now Alokai! Learn More
Throwing Errors

Throwing Errors in Middleware

This section covers the practical tools you'll use every day when handling errors in middleware.


Your Main Tool: context.createHttpError()

When you need to throw an error in a middleware endpoint, use context.createHttpError(). It ensures the error has:

  • A proper HTTP status code (404, 409, 500, etc.)
  • A human-readable message
  • Structured data the frontend can parse

When to use it

Use context.createHttpError() in these situations:

  • Missing or invalid request parameters — Throw 400 Bad Request
  • Vendor returns success with error indicator — Check response payload, throw appropriate error
  • Custom error messages for frontend — Transform technical errors into user-friendly ones

Basic pattern

// Check request parameters
if (!args.id) {
  throw context.createHttpError({
    statusCode: 400,
    message: 'Product ID is required',
    data: { field: 'id' },
  });
}

Always include the data property with structured information. Your frontend can use this to show specific error messages or highlight form fields.


Error Adapters for HTTP Clients

When your integration calls external APIs, errors need to be normalized to HttpError with proper status codes. Alokai provides error adapter packages for different HTTP clients (Axios, Apollo Client, etc.).

How Adapters Work

Adapters are typically configured once when creating your HTTP client instance. They automatically intercept and normalize all errors:

// Setup in index.server.ts or client factory
const client = adapter.withErrorNormalizer(
  httpClient,
  {
    extractMessage: (payload) => {
      // Vendor-specific message extraction
      return payload?.errors?.[0]?.message;
    },
  },
);

// Now all errors from this client are automatically normalized

When Adapters Are Already Configured

Most integrations configure error adapters in index.server.ts or client factory files. Once configured:

  • No try/catch needed in your endpoint methods
  • Errors are automatically normalized with correct status codes
  • Custom message extraction is already configured per vendor
// In your endpoint - no error handling needed
export const getProducts = async (context, args) => {
  const { api } = await context.getApiClient();
  
  // Errors automatically normalized by adapter
  return await api.getProducts({ categoryId: args.categoryId });
};

Check your integration's setup files (index.server.ts, apolloClient.ts) to see if adapters are already configured. If they are, you don't need to add error handling in most endpoint methods.


When to Use context.createHttpError()

Use context.createHttpError() for cases adapters don't handle:

  • Missing or invalid request parameters — Throw 400 Bad Request
  • Vendor returns success with error indicator — Check response payload, throw appropriate error
  • Custom error messages for frontend — Transform technical errors into user-friendly ones

Example: SAP out of stock

SAP returns a success response but includes statusCode: 'noStock' in cartModifications:

const { data } = await api.addCartEntry({ ... });

// Check for error indicator in successful response
if (data?.cartModifications?.find(m => m.statusCode === 'noStock')) {
  throw context.createHttpError({
    statusCode: 409, // Conflict
    message: 'Product is out of stock',
    data: { errors: [{ type: 'InsufficientStockError' }] },
  });
}

Why 409 Conflict? This is a business constraint, not a server error. Using 409 allows your frontend to show a specific "out of stock" message instead of generic "something went wrong".


Domain Errors: Use Sparingly

Middleware can also throw domain errors like ValidationError, NotFoundError, and UnauthorizedError. These automatically map to HTTP status codes:

  • ValidationError → 422 Unprocessable Entity (or 400 if thrown without issues)
  • NotFoundError → 404 Not Found
  • UnauthorizedError → 401 Unauthorized

When to use domain errors

  • Middleware-level validation (rare — most validation happens in frontend or external API)
  • Shared validation logic between multiple endpoints

Don't overuse domain errors in middleware. Most of the time, context.createHttpError() is simpler and more explicit.

ValidationError with Standard Schema

ValidationError has special support for schema validation libraries like zod, valibot, and arktype. Uncaught schema validation errors are automatically normalized to ValidationError with HTTP 422 status.

import { z } from 'zod';

// ZodError is automatically normalized to ValidationError
const schema = z.object({ email: z.email() });
const validated = schema.parse(args); // Throws ZodError if invalid

See Validation Errors for full documentation on schema validation support.


Custom Error Types

You can create custom errors by extending AppError:

import { AppError } from '@alokai/connect/middleware';

export class PaymentGatewayError extends AppError {
  constructor(gatewayCode: string, cause?: unknown) {
    super('Payment gateway returned an error', {
      cause,
      data: { gatewayCode },
    });
  }
}

When to create custom errors

  • You need to catch and retry specific error types
  • You're building a shared library used across integrations
  • Standard errors don't clearly express what failed

Most middleware endpoints don't need custom errorscontext.createHttpError() is usually sufficient.


Common Mistakes

❌ Throwing plain Error objects

// DON'T
throw new Error('Product not found');

Problem: Middleware can't extract a status code. Frontend gets 500 instead of 404.

Fix: Use context.createHttpError() or a domain error.


❌ Letting external errors escape

// DON'T
const { data } = await axios.get(url); // No try/catch!

Problem: If Axios throws, the error isn't normalized. Circuit breaker sees it as infrastructure failure.

Fix: Wrap in try/catch and use normalizeAxiosError().


❌ Exposing vendor details

// DON'T
throw context.createHttpError({
  message: JSON.stringify(vendorError), // Leaks internal details
});

Problem: Exposes vendor-specific error codes and stack traces to frontend.

Fix: Create a user-friendly message. Store vendor details in cause for debugging.


Quick Reference

ToolWhen to Use
context.createHttpError()Missing params, vendor payload errors, custom messages
Error adaptersConfigure once in client factory, auto-normalizes all errors
ValidationErrorSchema validation with zod/valibot (auto-maps to 422)
NotFoundErrorResource not found (auto-maps to 404)
Custom AppErrorSpecific retry logic, shared libraries

Next Steps