How to Debug OmniRoute: A Complete Guide to Multi-Layer Troubleshooting
To debug OmniRoute effectively, set APP_LOG_LEVEL=debug and OMNIROUTE_PROXY_FETCH_DEBUG=true, then trace the unique request ID through the pipeline from Next.js API routes to the executor layer using the Dashboard's Traffic Inspector and Translator Playground.
OmniRoute is a complex, modular router that stitches together dozens of LLM providers, streaming engines, and guardrails across multiple processes. Because components like the Next.js API routes, open-sse streaming workspace, MCP server, and MITM proxy run in different contexts, successful debugging requires a systematic, layered approach that tracks requests from ingress to upstream provider.
Understanding the Nine Debugging Layers
OmniRoute's architecture spans nine distinct layers where issues can originate. Debugging efficiently means knowing which layer to inspect based on your symptoms.
Layer 1: Request-Level Logs
The entry point for all API calls lives in src/app/api/v1/**/route.ts (e.g., chat/completions/route.ts). These routes generate the initial request ID and log authentication header sanitization. Set APP_LOG_LEVEL=debug in your environment to surface these logs, or enable the Debug Mode toggle in Dashboard → Settings → Advanced.
Layer 2: Context Manager
The open-sse/contextManager.ts module creates a per-request context object that carries metadata—including the request ID, target provider, combo configuration, and rate-limit info—throughout the pipeline. These logs appear automatically when APP_LOG_LEVEL is set to debug.
Layer 3: Combo Routing
The combo resolution logic in open-sse/services/combo.ts determines target resolution, strategy selection, and fallback decisions via the resolveComboTargets() function. Enable debugMode or use the Traffic Inspector tool in the Dashboard to see the ordered list of resolved targets for any given request.
Layer 4: Translator and Transformer
Format conversion between OpenAI, Anthropic, Gemini, and other providers happens in open-sse/translator/ and open-sse/transformer/. Use the Dashboard → Translator playground to see the raw upstream request and final downstream response for debugging translation mismatches.
Layer 5: Executor
Provider-specific request building, header construction, retries, and proxy routing occur in open-sse/executors/ (e.g., default.ts, cursor.ts). Set OMNIROUTE_PROXY_FETCH_DEBUG=true to emit [ProxyFetch] debug lines for every proxy-relay call, revealing the actual proxy name and egress details.
Layer 6: Guardrails
Prompt-injection protection and PII redaction operate from src/lib/guardrails/. These modules write concise [Guardrail] log lines when modifying or blocking payloads. Enable the Tool-source diagnostics toggle in Dashboard → Settings → Debug to see which tool definition each tool originated from.
Layer 7: MCP and A2A
Tool invocation logs, scope checks, and JSON-RPC flow are handled by open-sse/mcp-server/ and src/lib/a2a/. The MCP server writes per-tool audit rows to the SQLite mcp_audit table, viewable via the Traffic Inspector UI.
Layer 8: Database and Persistence
Call-log trimming, quota snapshots, and compression stats are managed in src/lib/db/ modules. If you encounter "deleteCallLogRowsByIds too many SQL variables" errors, verify that the log-trimmer in src/lib/db/callLogs.ts is chunking deletions automatically (≤500 per statement).
Layer 9: File-System Artifacts
Legacy log files in ${DATA_DIR}/log.txt and call_logs/ directories provide backward-compatible raw request/response dumps when APP_LOG_LEVEL=debug is enabled. These are maintained by src/lib/db/healthCheck.ts.
Step-by-Step Debugging Workflow
Follow this systematic approach to isolate issues in OmniRoute:
-
Reproduce the issue locally by running the dev server with
npm run dev. -
Identify the request ID from the first line of every request log, which contains a UUID like
req=xxxx. -
Trace through the pipeline by grepping the request ID in logs to see context creation (
contextManager), combo resolution (combo.ts), translator input/output (translator/index.ts), and executor calls (executors/*). -
Enable fine-grained debug:
- Set
APP_LOG_LEVEL=debugto surface all internalpinologs. - Set
OMNIROUTE_PROXY_FETCH_DEBUG=truefor low-level fetch diagnostics. - Activate the UI Debug Mode toggle to reveal hidden sidebar panels (Translator, Playground, Search Tools).
- Set
-
Use Dashboard tools:
- Translator Playground: Paste a request payload to see the exact upstream request, edit parameters, and re-run.
- Traffic Inspector: Visualizes each tool call, combo target, and proxy hop.
- Live Monitor: Streams raw SSE chunks from live requests for real-time inspection.
-
Check guardrail logs for
[Guardrail]entries indicating modified or blocked payloads. -
Inspect the database using SQLite queries or run specific tests like
npm run typecheck:core && node --import tsx/esm --test tests/unit/call-log-trim-sql-vars-5217.test.tsto verify SQLite limits.
Common Pitfalls and Quick Fixes
| Symptom | Likely Cause | Quick Fix |
|---|---|---|
| Empty response body | Provider returned no data but executor suppressed the error due to insufficient logging. | Set APP_LOG_LEVEL=debug and look for "[Executor] response empty" lines. |
| Tool list truncation | Legacy hard-coded MAX_TOOLS_LIMIT=128. |
Update to the latest version where chatcore/tools.ts detects Opencode clients and only truncates when provider-specific limits are known. |
| Missing proxy information | [ProxyEgress] logged proxy=direct incorrectly. |
Ensure proxy context is threaded through AsyncLocalStorage and APP_LOG_LEVEL=debug is set to see the actual proxy name in [ProxyEgress] lines. |
| SQLite "Too many SQL variables" | deleteCallLogRowsByIds attempted single IN (...) with >999 IDs. |
The truncation logic in src/lib/db/callLogs.ts now batches deletions (≤500 per statement). |
| Unexpected guardrail redaction | PII_REDACTION_ENABLED or PII_RESPONSE_SANITIZATION set to true. |
Verify these env vars in src/lib/guardrails/pii-masker.ts are unset unless intentional. |
| MCP tool-routing confusion | Tool-source diagnostics disabled. | Enable the Tool-source diagnostics toggle; the inspector will label each tool with its originating module. |
Essential Debug Configuration
Configure your environment for comprehensive debugging with these settings:
export APP_LOG_LEVEL=debug
export OMNIROUTE_PROXY_FETCH_DEBUG=true
npm run dev
Fetch a specific request's logs by ID:
grep -R "req=123e4567-e89b-12d3-a456-426614174000" logs/
Programmatically trace requests with custom IDs:
import { v4 as uuidv4 } from "uuid";
const requestId = uuidv4();
fetch("http://localhost:3000/api/v1/chat/completions", {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-omniroute-request-id": requestId,
},
body: JSON.stringify({
model: "gpt-4o",
messages: [{ role: "user", content: "debug me" }]
}),
});
Inspect call logs directly in SQLite:
sqlite3 ~/.omniroute/omniroute.db "SELECT id, request, response FROM call_logs WHERE request_id='123e4567-e89b-12d3-a456-426614174000';"
Key Source Files for Debugging
When stepping through the request flow, reference these specific files in the OmniRoute repository:
src/app/api/v1/chat/completions/route.ts: Request validation, auth extraction, and routing toopen-sse.open-sse/services/combo.ts: ContainsresolveComboTargets()for combo resolution and fallback logic.open-sse/translator/index.ts: Format conversion pipelines for provider-specific translations.open-sse/executors/base.ts: Retry logic, header building, and proxy handling implementations.src/lib/guardrails/pii-masker.ts: Redaction behavior controlled byPII_REDACTION_ENABLED.open-sse/mcp-server/server.ts: Tool registration, audit logging, and scope enforcement.src/mitm/server.cjs: MITM proxy for TLS/HTTPS inspection at the network level.docs/reference/ENVIRONMENT.md: Complete list of debug toggles and environment variables.src/app/dashboard/settings/page.tsx: Implementation of the Debug Mode UI switch.src/lib/db/callLogs.ts: Handles SQLite bound-parameter limits with chunked deletions.
Summary
- OmniRoute debugging requires a layered approach spanning nine architectural levels from API entry points to database persistence.
- Always obtain the request ID first to trace execution through
contextManager,combo.ts, translators, and executors. - Enable
APP_LOG_LEVEL=debugfor comprehensive logging andOMNIROUTE_PROXY_FETCH_DEBUG=truefor network-level diagnostics. - Use the Dashboard tools—Traffic Inspector, Translator Playground, and Live Monitor—for visual debugging of combo routing and translations.
- Reference specific source files like
open-sse/executors/base.tsandsrc/lib/db/callLogs.tswhen investigating executor behavior or database errors.
Frequently Asked Questions
How do I enable debug mode in OmniRoute?
Set the environment variable APP_LOG_LEVEL=debug before starting the server, and toggle the Debug Mode switch in the Dashboard under Settings → Advanced. This combination surfaces internal pino logs and reveals hidden debugging panels in the UI, including the Translator Playground and Traffic Inspector.
Where can I find the request ID to trace a specific call?
The request ID appears as a UUID in the first line of every request log (format: req=xxxx). You can also generate and pass your own request ID using the x-omniroute-request-id header when making API calls, then grep for this ID in the logs or query the SQLite call_logs table directly.
Why am I seeing "Too many SQL variables" errors in the logs?
This occurs when the call-log trimming logic attempts to delete too many rows at once (historically >999 IDs in a single IN clause). The fix is implemented in src/lib/db/callLogs.ts, which now automatically chunks deletions into batches of 500 or fewer. Update to the latest version to resolve this SQLite limitation.
How do I debug why a tool is not appearing or being truncated?
Check the Tool-source diagnostics toggle in Dashboard → Settings → Debug to see which module originated each tool definition. If tools are truncated, verify you're running the latest version where chatcore/tools.ts detects Opencode clients and only applies truncation when provider-specific limits are known, rather than the legacy hard-coded MAX_TOOLS_LIMIT=128.
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 →