OmniRoute Error Sanitization and Message Handling Pattern Explained
OmniRoute implements a centralized error-handling pipeline that prevents stack traces, file paths, and credentials from ever reaching clients by funneling all errors through a single sanitization layer.
The OmniRoute project, maintained at diegosouzapw/OmniRoute, enforces strict security guarantees for error responses across its entire API surface. Every handler, SSE stream writer, and combo-diagnostics module delegates error construction to a dedicated utilities layer. This article examines the implementation in open-sse/utils/error.ts and demonstrates how the pattern achieves defense-in-depth for production deployments.
Core Sanitization Functions
Three primary functions form the foundation of OmniRoute's error sanitization. Each operates at a different level of abstraction, from simple string cleaning to full payload reconstruction.
sanitizeErrorMessage
The sanitizeErrorMessage(message) function applies the first line of defense. Located at open-sse/utils/error.ts#L63-L74, it performs these operations in sequence:
- Truncates messages exceeding length limits
- Tokenizes the first line to drop stack trace continuations
- Replaces absolute POSIX and Windows paths with the literal
<path> - Redacts data URLs, authentication headers, and key-like tokens
This function is universally applied to every user-facing error string before transmission.
sanitizeUpstreamDetails
Upstream providers may return arbitrary JSON payloads containing sensitive metadata. The sanitizeUpstreamDetails(value, depth = 0) function at open-sse/utils/error.ts#L88-L104 recursively sanitizes these responses with configurable guards:
- Depth limitation: Hard stops at
MAX_DEPTH = 4 - Key blocking: Drops properties matching the
BLOCKED_KEYScredential regex - String sanitization: Runs all string values through
sanitizeErrorMessage - Array capping: Limits arrays to 32 elements
buildErrorBody
The buildErrorBody(statusCode, message, upstreamDetails?, classification?) function at open-sse/utils/error.ts#L121-L146 constructs the final response structure. It:
- Looks up default
typeandcodevalues from HTTP status viagetErrorInfo - Sanitizes the supplied message
- Optionally attaches cleaned upstream details under
upstream_details - Returns an OpenAI-compatible schema:
{ error: { message, type?, code? }, upstream_details? }
High-Level Error Response Helpers
Four exported helpers abstract the core functions for different response contexts.
| Helper | Purpose | Source Location |
|---|---|---|
errorResponse(statusCode, message) |
JSON responses from non-streaming handlers | open-sse/utils/error.ts#L443-L50 |
writeStreamError(writer, statusCode, message) |
SSE stream error events | open-sse/utils/error.ts#L58-L66 |
errorResponseWithComboDiagnostics(status, msg, diagnostics, opts) |
Combo routing failures with sanitized diagnostic headers | open-sse/utils/error.ts#L86-L131 |
createErrorResult(...) |
Internal pipeline representation carrying raw message for classification while exposing sanitized response | open-sse/utils/error.ts#L527-L588 |
The errorResponseWithComboDiagnostics helper deserves special attention. When combo routing terminates, it builds a response that simultaneously:
- Contains the standard sanitized error body
- Embeds a sanitized diagnostic trace in custom
x-omniroute-*headers - Adds the same trace under
diagnosticsin the JSON payload - Optionally includes recovery hints via
x-omniroute-recovery-*headers
Error Handling in the Request Pipeline
All HTTP API entry points eventually delegate to these helpers. The following excerpts from handler files demonstrate consistent application.
Chat Handler Validation
// src/sse/handlers/chat.ts
import { errorResponse } from "@omniroute/open-sse/utils/error.ts";
if (!model) return errorResponse(HTTP_STATUS.BAD_REQUEST, "Missing model");
Line 454 of this file shows validation failures funneled through the sanitization layer.
Reasoning Routing Handler
// src/sse/handlers/reasoningRouting.ts
return errorResponse(HTTP_STATUS.SERVICE_UNAVAILABLE, msg);
Upstream failures receive identical treatment.
SSE Streaming Errors
// src/sse/handlers/chatHelpers.ts
await writeStreamError(writer, HTTP_STATUS.UNAUTHORIZED, message);
Streaming contexts use writeStreamError to emit clean JSON payloads directly into the SSE stream.
These patterns repeat across src/sse/handlers/*.ts. Search for errorResponse( imports to locate all usage sites.
Specialized Error Types
OmniRoute provides domain-specific helpers for operational scenarios.
Provider Circuit-Breaker
The providerCircuitOpenResponse function returns HTTP 503 with:
Retry-Afterheader for client backoff- Machine-readable
code: "provider_circuit_open"
Model Cooldown
The modelCooldownResponse function returns HTTP 429 with:
- Structured
model_cooldownbody Retry-Afterheader indicating cooldown expiration
Both helpers internally invoke sanitizeErrorMessage, maintaining the same security guarantees.
Implementation Examples
Basic API Route Error
import { errorResponse } from "@omniroute/open-sse/utils/error.ts";
export async function POST(req: Request) {
const body = await req.json();
if (!body.prompt) {
return errorResponse(400, "Missing required field: prompt");
}
// Normal processing continues...
}
The raw message "Missing required field: prompt" passes through sanitizeErrorMessage before reaching the client.
Streaming Context Error
import { writeStreamError } from "@omniroute/open-sse/utils/error.ts";
async function streamResponse(writer: WritableStreamDefaultWriter<Uint8Array>) {
try {
const data = await fetchRemote();
// ...stream data...
} catch (e) {
await writeStreamError(writer, 502, e);
}
}
The raw exception e is never serialized directly—only its sanitized representation appears in the stream.
Combo Routing with Diagnostics
import { errorResponseWithComboDiagnostics } from "@omniroute/open-sse/utils/error.ts";
const diagnostics = {
poolSize: 12,
attempted: 5,
excluded: [{ provider: "openai", model: "gpt-4o-mini", reason: "rate_limit" }],
attemptOrder: [{ provider: "anthropic", model: "claude-3" }],
terminalReason: "all_candidates_exhausted",
recovery: { action: "try-auto", next_step: "Switch to auto-combo mode" },
};
return errorResponseWithComboDiagnostics(503, "Combo exhausted", diagnostics);
Diagnostic objects are recursively sanitized before appearing in headers or JSON payloads.
Key Files Reference
| File | Role |
|---|---|
open-sse/utils/error.ts |
Central sanitization and response factory—the core of the pattern |
src/shared/utils/apiResponse.ts |
Higher-level management route responses (delegates to streaming utils for sanitization) |
src/sse/handlers/chat.ts |
Handler demonstrating errorResponse usage |
src/sse/handlers/chatHelpers.ts |
SSE streaming with writeStreamError |
src/sse/handlers/reasoningRouting.ts |
Upstream failure handling |
tests/unit/combo/recovery-hint.test.ts |
End-to-end validation of header sanitization |
Summary
- Single source of truth: All errors route through
open-sse/utils/error.ts - Layered sanitization: String cleaning → recursive payload cleaning → structured response assembly
- No leakage guarantee: Stack traces, paths, credentials, and upstream internals never reach clients
- OpenAI compatibility: Standardized error schema eases client integration
- Operational visibility: Diagnostic headers and recovery hints maintain debugging utility without compromising security
Frequently Asked Questions
How does OmniRoute prevent credential leakage in error messages?
OmniRoute applies sanitizeErrorMessage to every user-facing string. This function redacts data URLs, authentication headers, and key-like tokens using pattern matching. Additionally, sanitizeUpstreamDetails drops any JSON property matching the BLOCKED_KEYS regex before serialization.
What is the maximum recursion depth for upstream error sanitization?
The sanitizeUpstreamDetails function enforces MAX_DEPTH = 4 to prevent performance degradation on deeply nested upstream responses. Arrays are additionally capped at 32 elements, and all strings undergo the standard sanitization pass.
Can I include debugging information in production error responses?
Yes—use errorResponseWithComboDiagnostics to attach sanitized diagnostic traces. These appear in both custom x-omniroute-* headers and the JSON payload under diagnostics. The same sanitization rules apply, ensuring no sensitive data escapes.
Does OmniRoute support custom error classifications?
The buildErrorBody function accepts an optional classification parameter that feeds into the error type/code lookup. Specialized helpers like providerCircuitOpenResponse and modelCooldownResponse demonstrate predefined classifications for operational scenarios.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →