# How to Debug OmniRoute: A Complete Guide to Multi-Layer Troubleshooting

> Effectively debug OmniRoute by enabling debug logs and tracing requests. Learn to troubleshoot your multi-layer pipeline with this comprehensive guide.

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

---

**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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`](https://github.com/diegosouzapw/OmniRoute/blob/main/default.ts), [`cursor.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/db/healthCheck.ts).

## Step-by-Step Debugging Workflow

Follow this systematic approach to isolate issues in OmniRoute:

1. **Reproduce the issue locally** by running the dev server with `npm run dev`.

2. **Identify the request ID** from the first line of every request log, which contains a UUID like `req=xxxx`.

3. **Trace through the pipeline** by grepping the request ID in logs to see context creation (`contextManager`), combo resolution ([`combo.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/combo.ts)), translator input/output ([`translator/index.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/translator/index.ts)), and executor calls (`executors/*`).

4. **Enable fine-grained debug**:
   - Set `APP_LOG_LEVEL=debug` to surface all internal `pino` logs.
   - Set `OMNIROUTE_PROXY_FETCH_DEBUG=true` for low-level fetch diagnostics.
   - Activate the UI **Debug Mode** toggle to reveal hidden sidebar panels (Translator, Playground, Search Tools).

5. **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.

6. **Check guardrail logs** for `[Guardrail]` entries indicating modified or blocked payloads.

7. **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.ts` to 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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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:

```bash
export APP_LOG_LEVEL=debug
export OMNIROUTE_PROXY_FETCH_DEBUG=true
npm run dev

```

**Fetch a specific request's logs by ID:**

```bash
grep -R "req=123e4567-e89b-12d3-a456-426614174000" logs/

```

**Programmatically trace requests with custom IDs:**

```typescript
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:**

```bash
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`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/app/api/v1/chat/completions/route.ts)**: Request validation, auth extraction, and routing to `open-sse`.
- **[`open-sse/services/combo.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/services/combo.ts)**: Contains `resolveComboTargets()` for combo resolution and fallback logic.
- **[`open-sse/translator/index.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/index.ts)**: Format conversion pipelines for provider-specific translations.
- **[`open-sse/executors/base.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/executors/base.ts)**: Retry logic, header building, and proxy handling implementations.
- **[`src/lib/guardrails/pii-masker.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/guardrails/pii-masker.ts)**: Redaction behavior controlled by `PII_REDACTION_ENABLED`.
- **[`open-sse/mcp-server/server.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`](https://github.com/diegosouzapw/OmniRoute/blob/main/docs/reference/ENVIRONMENT.md)**: Complete list of debug toggles and environment variables.
- **[`src/app/dashboard/settings/page.tsx`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/app/dashboard/settings/page.tsx)**: Implementation of the Debug Mode UI switch.
- **[`src/lib/db/callLogs.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`](https://github.com/diegosouzapw/OmniRoute/blob/main/combo.ts), translators, and executors.
- **Enable `APP_LOG_LEVEL=debug`** for comprehensive logging and `OMNIROUTE_PROXY_FETCH_DEBUG=true` for 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.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/executors/base.ts) and [`src/lib/db/callLogs.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/db/callLogs.ts) when 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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`](https://github.com/diegosouzapw/OmniRoute/blob/main/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`.