# How OmniRoute Handles Error Handling and Response Sanitization

> Discover how OmniRoute handles error handling and response sanitization using its dedicated module to emit safe structured JSON payloads before client response.

- Repository: [Diego Rodrigues de Sa e Souza/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- Tags: how-to-guide
- Published: 2026-07-20

---

**OmniRoute centralizes every error path through the [`open-sse/utils/error.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/utils/error.ts) module, where `sanitizeErrorMessage` and `buildErrorBody` strip sensitive internals and emit a safe, structured JSON payload before any response reaches the client.**

The `diegosouzapw/OmniRoute` repository treats error leakage as a critical security risk. Its approach to **error handling and response sanitization** relies on a small set of tightly controlled utility functions that remove stack traces and absolute file paths from all non-streaming and streaming responses.

## Core Sanitization Utilities in [`open-sse/utils/error.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/utils/error.ts)

The error pipeline is built on two primary helpers exported from [`open-sse/utils/error.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/utils/error.ts).

### `sanitizeErrorMessage`

**`sanitizeErrorMessage`** truncates an error down to its first line and scrubs stack traces, absolute paths, and any other potentially sensitive metadata. According to the OmniRoute source code, every catch block that returns an error to the client must call this function before exposing any text.

### `buildErrorBody` and `buildStreamErrorChunks`

**`buildErrorBody`** accepts an HTTP status code and a sanitized message, then returns a JSON object that conforms to the API error contract: `{ error: { message, type?, code? } }`. For streaming endpoints, **`buildStreamErrorChunks`** performs the same transformation but packages the result into Claude-compatible SSE error frames.

## The Four-Step Error Handling Workflow

OmniRoute enforces a uniform pattern across all route handlers and stream constructors:

1. **Catch** the exception inside the route or service.
2. **Sanitize** the error via `sanitizeErrorMessage(err)` or `sanitizeErrorMessage(err?.message)`.
3. **Build** a structured payload using `buildErrorBody(status, sanitizedMessage)` or SSE-specific helpers.
4. **Return** the safe payload as the HTTP response, or enqueue it into the SSE stream.

## Sanitizing Errors in Standard HTTP Routes

Below is the typical pattern found in Next.js API routes such as [`src/app/api/playground/presets/route.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/app/api/playground/presets/route.ts).

```typescript
// src/app/api/playground/presets/route.ts
import { buildErrorBody, sanitizeErrorMessage } from "@omniroute/open-sse/utils/error.ts";

export async function POST(req: Request) {
  try {
    // normal handler logic
  } catch (err) {
    const safeMsg = sanitizeErrorMessage(err);
    return new Response(JSON.stringify(buildErrorBody(500, safeMsg)), {
      status: 500,
      headers: { "Content-Type": "application/json" },
    });
  }
}

```

In this flow, `sanitizeErrorMessage` prevents raw `Error` objects from reaching the client, while `buildErrorBody` guarantees a consistent JSON envelope.

## Handling Errors in SSE Streams

Streaming endpoints in OmniRoute introduce additional complexity because errors must be emitted as SSE events rather than plain JSON responses. The repository solves this in [`open-sse/handlers/chatCore.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/handlers/chatCore.ts) through **`createDisconnectAwareStream`**.

### Upstream Error Conversion

When an upstream provider returns an error during a chat completion stream, the handler converts it into a sanitized SSE chunk as shown in this excerpt:

```typescript
// open-sse/handlers/chatCore.ts
import { sanitizeErrorMessage, buildStreamErrorChunks } from "./utils/error.ts";

function handleUpstreamError(upstreamError: Error) {
  const safeMsg = sanitizeErrorMessage(upstreamError.message);
  // For Claude-compatible streams:
  return buildStreamErrorChunks(safeMsg, 502, null);
}

```

### The `createDisconnectAwareStream` Controller

For generic SSE streams, `createDisconnectAwareStream` detects upstream failures, applies `sanitizeErrorMessage`, and emits an `event: error` frame followed by the sanitized payload. The implementation also sends a terminal `event: message_stop` frame for Claude-compatible streams so clients receive a clean close even after an error.

```typescript
// open-sse/handlers/chatCore.ts
function createDisconnectAwareStream(controller) {
  controller.error = (upstreamError) => {
    const safeMsg = sanitizeErrorMessage(upstreamError.message);
    controller.enqueue(
      encodeSseEvent("error", { type: "server_error", message: safeMsg })
    );
    // close stream cleanly
  };
}

```

This ensures that **no raw stack trace or file system path ever leaks to the client**, satisfying Hard Rule #12 as implemented in the OmniRoute source code.

## Enforcement and Automated Testing

Sanitization is not merely a convention; it is enforced by the test suite. The file [`tests/unit/rule12-error-sanitization-sweep.test.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/tests/unit/rule12-error-sanitization-sweep.test.ts) contains unit tests that verify every error path invokes the sanitizer. Additionally, lint-time checks confirm that source files import `sanitizeErrorMessage` wherever catch blocks return errors to clients.

## Summary

- OmniRoute centralizes error handling in [`open-sse/utils/error.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/utils/error.ts).
- **`sanitizeErrorMessage`** strips stack traces and file paths, keeping only the first line of the error.
- **`buildErrorBody`** wraps sanitized messages into `{ error: { message, type?, code? } }`.
- For SSE streams, `buildStreamErrorChunks` and `createDisconnectAwareStream` emit sanitized `event: error` frames.
- Hard Rule #12 is enforced by unit tests in [`tests/unit/rule12-error-sanitization-sweep.test.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/tests/unit/rule12-error-sanitization-sweep.test.ts) and lint checks that require the sanitizer import.

## Frequently Asked Questions

### What is Hard Rule #12 in OmniRoute?

Hard Rule #12 prohibits the exposure of raw error objects to API consumers. As implemented in `diegosouzapw/OmniRoute`, this means every caught exception must pass through `sanitizeErrorMessage` before being serialized into an HTTP or SSE response.

### How does OmniRoute prevent stack traces from leaking in SSE streams?

OmniRoute uses `createDisconnectAwareStream` in [`open-sse/handlers/chatCore.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/handlers/chatCore.ts) to intercept upstream errors. It calls `sanitizeErrorMessage` on the error text and emits an SSE `event: error` frame containing only the sanitized `type`, `code`, and `message`, ensuring internal stack details never reach the client.

### What is the difference between `buildErrorBody` and `buildStreamErrorChunks`?

**`buildErrorBody`** generates a static JSON object for standard REST responses, while **`buildStreamErrorChunks`** formats a sanitized message into Claude-compatible SSE data frames. Both utilities use the same underlying sanitizer but target different transport protocols.

### Where are OmniRoute's sanitization rules enforced beyond runtime?

Beyond runtime logic, OmniRoute enforces sanitization through [`tests/unit/rule12-error-sanitization-sweep.test.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/tests/unit/rule12-error-sanitization-sweep.test.ts), which acts as a regression suite for every error path. The project also runs lint-time checks that flag any source file missing the required `sanitizeErrorMessage` import where catch blocks are present.