Codex Desktop: concurrent SSH thread creation races title generation and surfaces false API "no credits" error

Open 💬 0 comments Opened Aug 25, 2026 by Riyasushin

What version of the Codex App are you using (From “About Codex” dialog)?

Codex Desktop 26.818.61809 (build 7019)

  • Local CLI: codex-cli 0.147.0
  • Remote SSH-host CLI/app-server: codex-cli 0.148.0

What subscription do you have?

ChatGPT subscription. Both the local and remote CLI report Logged in using ChatGPT; the CLI does not expose the exact subscription tier.

What platform is your computer?

Darwin 25.5.0 arm64 arm

The project runs on a Linux host connected through Codex Desktop's SSH remote-project feature.

What issue are you seeing?

When several new SSH-host tasks are created almost simultaneously, Codex Desktop races thread hydration/rollout initialization against automatic thread-title generation.

In one observed burst of five new remote tasks:

  • Desktop attempted to read newly created rollout JSONL files while they were still empty.
  • The renderer received turn/item events for conversations it had not registered yet.
  • Multiple automatic title-generation requests timed out.
  • One hidden structured turn used for title generation returned an API billing error even though both the local and remote Codex installations were authenticated with ChatGPT and had no API-key environment variables.
  • The UI surfaced the metadata failure as a reconnecting/stream-disconnected message, which made it look like the primary task had lost its connection.
  • Primary remote turns continued running, and a later direct remote codex exec request succeeded.

Exact sanitized error:

[ThreadMetadataGenerationService] Failed to generate thread title
errorMessage="Structured turn failed: stream disconnected before completion:
You have no credits remaining. Add credits to continue using the API at
https://platform.openai.com/settings/organization/billing/."

Adjacent errors from the same creation burst:

failed to read thread: thread-store internal error:
failed to read session metadata ... rollout ... is empty

Received turn/started for unknown conversation
Received item/started for unknown conversation
Conversation state not found

[ThreadMetadataGenerationService] Failed to generate thread title
errorMessage="Timed out waiting for structured result."

Authentication checks performed after the failure:

local:  codex login status -> Logged in using ChatGPT
remote: codex login status -> Logged in using ChatGPT

The running remote codex app-server proxy process had none of these variables:

OPENAI_API_KEY
CODEX_API_KEY
CODEX_ACCESS_TOKEN

The remote auth cache reported auth_mode=chatgpt. Its modification time predated the app-server process start, so this was not a mid-process switch from API-key authentication.

A minimal remote request with all API credential variables explicitly removed succeeded:

env -u OPENAI_API_KEY -u CODEX_API_KEY -u CODEX_ACCESS_TOKEN \
  codex exec --skip-git-repo-check --json "Reply with exactly OK"

{"type":"item.completed","item":{"type":"agent_message","text":"OK"}}
{"type":"turn.completed", ...}

This suggests the billing message was specific to the auxiliary metadata/title-generation path, not actual account-wide API credit exhaustion.

What steps can reproduce the bug?

Observed reproduction; not yet confirmed deterministic:

  1. Configure Codex Desktop with an SSH remote project.
  2. Authenticate Codex on the remote host using ChatGPT.
  3. Ensure the remote login shell can start codex app-server proxy.
  4. Create approximately five new remote tasks within a few seconds.
  5. Start a turn immediately in each new task.
  6. Observe Desktop attempting to hydrate/read the new threads before their rollout files contain metadata.
  7. Observe unknown conversation / empty-rollout errors and title-generation timeouts.
  8. One title-generation structured turn may return the API no credits remaining error and the UI may display a reconnecting/stream-disconnected state, while primary task turns continue.

Example affected remote thread:

01a037d2-1ba3-7b83-b0ee-4e28b98be7f5

Ephemeral/unknown conversation associated with the failed metadata turn:

01a037d3-b74b-7731-88e4-d64a8de34b1b

Sanitized UTC timeline:

07:28:31-07:28:32  five remote threads created; empty-rollout and unknown-conversation errors begin
07:29:06           thread title generation times out
07:30:37           title structured turn returns false API no-credits error
07:30:37           turn/completed received for an unknown ephemeral conversation
07:30:37           thread/name/set succeeds for a primary remote thread
07:30:46           additional title generations time out

What is the expected behavior?

  • A new thread should be registered and have valid initial metadata before Desktop hydrates it or routes its events.
  • Automatic title generation should use the same effective ChatGPT authentication context as the remote task.
  • An auxiliary title-generation failure should not be shown as a primary task stream disconnection.
  • Title generation should be isolated, queued, retried, or fall back to a local/default title without disrupting or confusing the main task UI.
  • API billing guidance should never be shown for a ChatGPT-authenticated metadata request unless the request actually used API-key authentication.

Additional information

This appears to involve two related failure boundaries:

  1. A thread-initialization race when several SSH-host tasks are created concurrently.
  2. Incorrect error/auth routing or UI attribution for the hidden structured turn used by ThreadMetadataGenerationService.

The primary turns continued producing reasoning/tool events while metadata generation failed. thread/name/set also succeeded after the failure, confirming that the title-generation error was non-fatal.

Potentially adjacent but not duplicate reports:

  • #32566 — includes unknown conversation and a separate title metadata error while rendering mixed-version MCP records.
  • #33153 — app-server restart can leave an accepted turn stuck and also causes title metadata failure.

Full logs contain private project paths, so only targeted sanitized excerpts are included here. More redacted timestamps or log lines can be provided if maintainers identify the relevant request/trace identifiers.

View original on GitHub ↗