Codex App create_thread worktree rows fail with 'Worktree init failed' and no recoverable error

Open 💬 3 comments Opened Jun 14, 2026 by johnsilvavlogs
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

What version of the Codex App are you using?

Codex App 26.609.41114 build 3888

Bundled CLI: codex-cli 0.140.0-alpha.2

Global CLI on the same machine: codex-cli 0.135.0

What platform is your computer?

macOS 26.3 build 25D125

What issue are you seeing?

A parent/orchestrator Codex thread attempted to create two worktree-backed project threads through the create_thread tool. The tool returned only pending worktree IDs, and the Codex sidebar then showed both child rows as:

Worktree init failed

The parent thread had no returned threadId, no follow-up API to inspect/cancel/resolve the pending worktree, and no useful error message explaining why init failed.

Observed pending IDs from the tool results:

{"pendingWorktreeId":"local:8afc1d65-0aeb-450b-9ec7-6f76b68bba58"}
{"pendingWorktreeId":"local:85344054-5e7f-49c2-a751-65872c865ceb"}

What steps can reproduce the bug?

From a visible Codex manager/orchestrator thread in a local Git project, call create_thread twice with a project worktree target similar to:

{
  "target": {
    "type": "project",
    "projectId": "/path/to/local/git/project",
    "environment": {
      "type": "worktree",
      "startingState": { "type": "working-tree" }
    }
  },
  "thinking": "xhigh",
  "prompt": "You are a managed direct-report thread..."
}

Actual result:

  1. create_thread returns only pendingWorktreeId.
  2. The sidebar creates rows for the pending workers.
  3. Within about one minute, both rows display Worktree init failed.
  4. The parent/orchestrator cannot inspect the failed pending worktree, cannot retrieve a failure reason, cannot send a correction, and cannot cancel or clean it up through the tool surface.

Diagnostic evidence from the local machine

After the failure:

  • No matching new directories existed under ~/.codex/worktrees for the two pending IDs.
  • No normal threads rows were created for the failed pending worktrees in ~/.codex/sqlite/state_5.sqlite.
  • Searching the live ~/.codex/sqlite/logs_2.sqlite around the failure time for the pending IDs, worktree, and failed did not expose an actionable worktree-init error.
  • git worktree add --detach HEAD /tmp/... from the same repo succeeded and was removed cleanly, so the base Git repository and filesystem permissions appear healthy.
  • The app-server was running from the bundled CLI and the Codex app was otherwise responsive.

Expected behavior

At minimum, failed pending worktree initialization should surface an actionable error to the parent/orchestrator and the UI.

One or more of these would make the workflow recoverable:

  1. create_thread returns a stable reserved threadId plus pendingWorktreeId, even before init completes.
  2. A pending-worktree API exists, for example read_pending_worktree(pendingWorktreeId), cancel_pending_worktree(pendingWorktreeId), and resolve_pending_worktree(pendingWorktreeId).
  3. The failed sidebar row can expose the exact failing command/stderr or a structured failure reason.
  4. list_threads or another tool can search pending/failed worktree rows by pendingWorktreeId.
  5. Failed pending worktree rows are cleanup-able through the tool surface.

Why this matters

This blocks visible manager/worker workflows in Codex Desktop. An orchestrator can request independent worker threads, but if Codex worktree setup fails, the parent is left with only a non-addressable pendingWorktreeId and a sidebar row saying Worktree init failed.

The user-facing failure is especially rough because the app visibly creates failed worker rows but the agent has no programmatic recovery path or error details.

Related issues

  • #26861 covers the broader API gap where create_thread returns pendingWorktreeId without an addressable threadId.
  • #27584 covers another tool-created worktree limitation around local environment setup.

This issue is specifically about the pending worktree reaching a visible Worktree init failed state with no actionable error, no persisted thread, and no tool-level recovery path.

View original on GitHub ↗

3 Comments

github-actions[bot] contributor · 2 months ago

Potential duplicates detected. Please review them and close your issue if it is a duplicate.

  • #26861

Powered by Codex Action

jomoskus · 1 month ago

I can add a fully diagnosed reproduction of this same failure and recovery gap.

Environment

  • Codex Desktop 26.715.52143, build 5591
  • Bundled codex-cli 0.145.0-alpha.18
  • macOS 26.5.2 / arm64

Repository layout and reproduction

The saved Codex project pointed at an umbrella directory:

workspace/             # saved project root; not itself inside Git
  repo/                 # bare Git common-dir
  linked-worktree-a/
  linked-worktree-b/
  ...

Two worktree-backed create_thread calls returned only:

client-new-thread:997da77f-f8a7-47fa-9a8c-f77158be7e8e
client-new-thread:e627de81-af95-4ae0-8e07-85fcc301063d

Both later showed Worktree init failed, never received a regular threadId, and never appeared in list_threads.

Confirmed root cause

Codex resolves the source repository by running:

git rev-parse --show-toplevel

with the saved project root as sourceWorkspaceRoot. At the umbrella root this exits 128:

fatal: not a git repository (or any of the parent directories): .git

Git does not search child directories, so the bare common-dir and valid linked worktrees below the umbrella are irrelevant to this probe.

Inspection of the bundled Desktop implementation confirms this exact chain:

  1. repository resolution runs rev-parse --show-toplevel;
  2. the “not a git repository” result resolves to no repository;
  3. managed worktree creation throws exactly Not a git repository;
  4. this occurs before path allocation, git worktree add, branch selection, hooks, setup scripts, permissions, or worktree-count handling.

The provisioner catch path stores the message only on the in-memory pending-worktree entry and desktop notification. Persistent Codex logs contain the successful create_thread tool response returning the client ID, but not the later provisioning failure. Once the pending UI entry disappears, there is no queryable status or error keyed by that ID.

Verified workaround and fix

Local mode continued to work.

Registering a fully independent, ordinary non-bare clone as a separate saved project fixed Worktree mode. A controlled validation then showed:

  • pending client ID promoted to a real threadId;
  • managed cwd under $CODEX_HOME/worktrees;
  • --is-inside-work-tree=true;
  • --is-bare-repository=false;
  • detached HEAD at the expected commit;
  • clean status;
  • archive cleanup removed the managed worktree.

Using a linked checkout whose common-dir was the bare repository exposed a separate shared-config mutation bug, now reported as #34828.

Suggested improvements

  1. Preflight sourceWorkspaceRoot before accepting or queueing Worktree mode and return a synchronous, actionable error.
  2. Persist pending/failed provisioning status and sanitized stderr keyed by the returned client ID.
  3. Expose read/cancel/retry operations for pending worktrees, as discussed in #26861.
  4. For umbrella projects, allow an explicit child Git root or remembered default repository, as discussed in #26338.

The reliable workaround is Local mode or a saved project rooted in an independent ordinary non-bare clone.

jnyross · 18 days ago

Additional reproduction from jnyross/codex-graph Lisbon v4 dogfood (Codex Desktop, 2026-08-09).

Three create_thread calls for read-only research workers used environment: { type: "worktree" } on a saved Codex project. Each returned only:

{"clientThreadId":"client-new-thread:<uuid>","hostId":"local"}

The orchestrator polled list_threads for 120s and never observed the pending rows. The terminal is mac-vm-harness--codexgraph-test/candidates/frozen-lisbon-v4/terminal-lisbon-v4.json (blocked, all handles in pending_setup, unresolved risk "Required research starts failed: N2A, N2B, N2C").

This is the same silent pending-resolution class: the parent has no threadId, no error, and no pending-worktree API to recover. The skill fix (PR #14, v0.4.5) now preflights isGitRepository === true before any worktree create and degrades a single repository writer to a root-orchestrator write, which avoids the silent class for read-only workers.

See also #26861 for the related addressability gap.