Browse documentation
Jump to a section
Last updated

Codex Router Not Working? Troubleshooting & Fixes

Most Codex Router problems have a small set of causes: a missing credential, a disabled provider, a stale catalog, a stopped background service, or a configuration written by a different checkout. This page is the index of those failures and their fixes, adapted from the repository’s docs/TROUBLESHOOTING.md.

Start here: the doctor command

Every troubleshooting session begins the same way:

./bin/model-router codex doctor

Every FAIL line includes a targeted fix. To rebuild only repository-managed files, config and service state:

./bin/model-router codex doctor --fix

If a recognized older Kimi router is reported, add the migration flag:

./bin/model-router codex doctor --fix --migrate-known

Neither command prints credential values, and repair refuses unknown router owners. See the doctor deep dive for what each check covers.

Common issues and fixes

ClinePass returns a wrapped or unsuccessful response

The router now unwraps ClinePass’s successful non-streaming success: true / data completion into Chat Completions. An unsuccessful envelope is reported as a provider failure instead of being relayed as an apparently successful answer. Update the router if Codex shows an empty or malformed ClinePass turn.

Automatic service startup keeps failing

Repeated automatic startup probe failures now pause subsequent attempts for 1, 2, 4, 8, then at most 15 minutes; the log says backing off. After fixing the cause, an explicit service start or restart resets the cooldown. On Windows, ./codex-router.ps1 start --foreground again runs without claiming the managed service record; service stop and restart now report when shutdown cannot be verified.

Z.ai Coding Plan stops during a long reasoning pause

The stream now allows a separate three-minute idle deadline after its prologue. Set CODEX_ROUTER_ZAI_CODING_STREAM_STALL_MS to an integer from 1 to 240000 milliseconds in the service environment if needed, then reload the service definition. This does not change other providers’ deadlines.

Compaction fails on a custom OpenAI-Responses gateway

Generic OpenAI-Responses gateways that require streaming previously returned 400 Stream must be set to true during auto-compaction, leaving the conversation unable to continue. Compaction now streams like an ordinary turn and handles incomplete or failed streams through the usual failover path. Update the router if this error appears after a conversation fills its context.

Control Center stalls when Ollama is offline

Control Center snapshots now skip the Ollama CLI if the API probe already failed, and local model probes have short timeouts. A stopped Ollama runtime should no longer hold up the panel.

Refresh fails with ENOENT after upgrading Node

Router child processes now use the Node binary recorded by the installation, or the current interpreter as a fallback. This avoids refresh failures after brew upgrade node removes the old Homebrew Cellar path.

Windows service does not start after reboot

The service now allows up to 45 seconds for its initial process-identity probe and retries once on timeout. An ACL warning on the service-process record no longer stops startup; credential-file ACL failures still stop it.

External models are missing from the picker

The intended provider must report both SHOW and ready. Run ./bin/providers, ./bin/refresh-catalog and ./bin/doctor, then fully quit Codex, reopen it, and create a new task — closing only a window does not reload model_catalog_json. Full steps: models missing from the picker.

Routed model agents are missing

Pulling main only updates the source checkout. Apply it to the per-user install and verify the generated custom agents:

./bin/model-router codex update
./bin/model-router codex doctor

The doctor should report OK for Routed model agents; if not, run doctor --fix and restart Codex.

State directory belongs to another checkout

If doctor reports a state ownership failure, you are running from a clone that did not perform the install. Repair through the owning checkout with ./bin/model-router codex doctor --fix. It transfers ownership to the current checkout only when the recorded owner is gone, or when you set MODEL_ROUTER_ALLOW_FOREIGN_STATE=1.

Kimi OAuth is not ready

kimi login
./bin/model-router codex providers enable kimi-oauth
./bin/model-router codex doctor

The router reads the official Kimi CLI credential and refreshes it under a cross-process lock. Do not copy the OAuth token anywhere else.

Windows blocks the Grok OAuth CLI

If grok --version fails with spawn UNKNOWN, “An Application Control policy has blocked this file,” or a Smart App Control notification, use the grok-api provider with an xAI API key instead. See the Windows guide for the exact commands.

An API key is missing or invalid

Re-run the hidden set prompt and check status:

./bin/model-router codex provider-key deepseek set
./bin/model-router codex provider-key deepseek status

Confirm the key belongs to the named system: Kimi OAuth, Kimi Platform, DeepSeek, Anthropic, Alibaba plan and Z.ai coding keys are all separate, non-interchangeable credentials.

A provider changed its model IDs

Compare the provider’s official model-list endpoint with the registry:

./bin/discover-models deepseek

Discovery is read-only. To use a newly discovered model locally before a registry release, curate it for your machine with ./bin/curate-models deepseek.

A routed slug fails with unrouted_model

The picker may have been rebuilt after a model was added or renamed while the background router still has the old registry in memory. Restart the service with ./bin/control service restart, then rerun doctor. If doctor reports a skipped user model, correct or remove that local curation entry. The router now fails an unknown provider/model slug locally instead of accidentally sending the prompt to ChatGPT as if it were a native model.

Old chatgpt-web/* models stopped loading

The unofficial ChatGPT Web browser-automation provider was removed because using it risked suspension or permanent loss of the operator’s OpenAI account. Stop using those routes and remove every stale curated slug with ./bin/curate-models chatgpt-web --remove <slug>. After updating, stale rows are skipped safely rather than routed, but remain in user-models.json until you remove them.

Native GPT models stopped working

Temporarily return Codex to its native base URL:

./bin/model-router codex disable

This removes only the marked block and current service; it preserves the selected model, profiles, provider credentials and ChatGPT login. If native models work again, inspect router health and create a support bundle.

Another process owns ports 4200–4203

lsof -nP -iTCP:4200 -iTCP:4201 -iTCP:4202 -iTCP:4203 -sTCP:LISTEN

Do not kill the process until its owner and purpose are known. The installer migrates only recognized earlier repository services and otherwise stops with a conflict.

The background service is stopped

In Control Center, open Status → Service health → Fix, then check Router health and return to a known working chat model. Fix repairs and restarts the installed Router, so it may interrupt routed chats; it does not enable a separate tool client such as OpenRouter Decisions.

launchctl print "gui/$(id -u)/io.github.codex-router"
./bin/model-router codex doctor --fix

Linux uses systemctl --user status codex-router.service; Windows uses Get-ScheduledTask -TaskName "Codex Router". Keep the repository at the absolute path used during installation, and rerun setup from the new path if it was moved.

On Windows, start and restart now check that the scheduled task actually exists before calling schtasks. If the task is missing you get a message naming the task plus service.mjs install and doctor --fix, instead of schtasks.exe’s own error and a false {"state":"running"}. Nothing is mutated on the way out.

A first install timed out after 300 seconds

A large catalog can make LiteLLM’s first cold start exceed the installer’s five-minute health wait even when the service and launchers were installed correctly. Current main reports retryable exit code 75 (EX_TEMPFAIL) and preserves the service, launchers and client configuration instead of uninstalling them. Follow the platform-specific service check above, wait for the service to become healthy, then run ./bin/model-router codex doctor --fix. A confirmed crash loop or missing launcher is still treated as a failed installation and rolled back.

An update failed

./bin/model-router codex rollback

Updates refuse edits to tracked files (untracked files never block an update; --force discards tracked edits), non-main development branches and unknown origin URLs rather than overwriting local work. Legacy migration rollback is separate: ./bin/migrate rollback.

A session ran past the context window instead of compacting

Codex decides when to auto-compact from the input_tokens each response reports. A provider that answers a large prompt with input_tokens: 0 leaves that counter flat, so the context bar looks nearly empty right up to the point the provider rejects the turn. The router substitutes an estimate of the prompt it just sent when — and only when — a routed response explicitly reports zero prompt tokens for a request that plainly carried a large one.

Substitutions are recorded rather than hidden: the usage event keeps the provider’s own numbers and adds estimatedInputTokens, and the router logs estimated-input-tokens=<count> on that turn. Count them in the state directory’s usage-events.jsonl:

grep -c estimatedInputTokens "$CODEX_HOME/codex-router/usage-events.jsonl"

Report zero-token responses to the provider — only they can fix the source. To see the provider’s own numbers in Codex again, set CODEX_ROUTER_ZERO_INPUT_ESTIMATE=0 in the service environment.

HTTP 200 appears, but the generation failed

HTTP 200 confirms delivery, not a completed model turn. Check the generation outcome in Control Center’s recent requests: failed, incomplete, canceled and indeterminate turns can still have billed tokens. Older usage records have no recorded outcome. If streamed text loses an unfinished literal reasoning tag or trailing whitespace, update the router; the stream adapter now flushes held text before completion without duplicating events.

Claude Code keeps generating after you cancel a request

Update to the current upstream main. Closing the Claude Code client connection now aborts the upstream Responses generation while waiting for headers or reading JSON or SSE, so a canceled request does not keep running in the background.

Non-streaming Responses contain broken Unicode

Update to the current upstream main. The router now decodes UTF-8 across HTTP chunks, including split characters in assistant text, tool arguments and metadata, instead of replacing them with �.

Retry usage appears lower than the provider’s billed total

Update to the current upstream main. When a retried attempt omits billed token counts, the router now falls back to that attempt’s reported input and output before summing billed usage; an explicit billed zero still remains zero. This corrects the recorded total without changing the provider’s own charges.

Responses WebSocket does not connect

Current releases accept the Responses WebSocket v2 upgrade. A 401 usually means Codex still has a stale managed URL: run ./bin/doctor --fix, fully quit Codex, then reopen it. A 426 carrying the supported OpenAI-Beta: responses_websockets=2026-02-06 hint means the attempted WebSocket contract did not match and Codex will fall back to HTTP; provider errors still arrive as normal Responses error events.

Voice Mode reports an unsupported /v1/live route

Codex Voice uses native realtime endpoints that are separate from the Responses API. Run ./bin/enable again after updating, fully quit Codex, and reopen it so the managed realtime overrides take effect.

Uninstall retained files

This is intentional. ./bin/uninstall removes only the active integration and background service; the state directory may contain credentials, logs, catalog caches, install history and rollback snapshots. Inspect it manually before deleting anything.

Create a support bundle

./bin/support-bundle

The generated mode-600 JSON includes versions, doctor checks, service state, provider presence, config ownership and file metadata—it excludes credential values, prompts, responses and log contents. The legacy --include-logs option is now a deprecated no-op because old logs can contain credentials that were later rotated or deleted. The tool never uploads a bundle automatically.

Still stuck?

Open an issue on the Codex Router repository and attach the redacted support bundle. Include the doctor output and the exact error text, but never paste a complete managed base URL or any credential.