Skip to content

opencode run --session --fork stalls with zero output when --dir changes to a Git worktree #46276

Closed as not planned

Description

@Great-Bucket

Description

opencode run --session <id> --fork completes when the child keeps the parent
session's directory, but can stall before emitting its first JSON event when
--dir changes to another Git worktree of the same repository.

The stalled process produces zero stdout and zero stderr until it is killed by
an external timeout. The reproduction is sequential: no two opencode run
processes overlap.

Environment

  • macOS 14.6.1 (23G93), Intel x86_64
  • Reproduced with OpenCode 1.17.11 and 1.18.25
  • opencode run --format json
  • Reproduced without a filesystem sandbox, permission overlay, or wrapper

Minimal reproduction

Start with a Git repository at [REPO_A] and create a second worktree:

git -C [REPO_A] worktree add --detach [REPO_B] HEAD

Create two equivalent one-turn parent sessions in [REPO_A], recording their
session IDs as [SAME_DIR_PARENT] and [CROSS_DIR_PARENT]. Use each parent only
once in the controls below.

Same-directory control — completes and emits step_start, text, and
step_finish:

printf '%s\n' 'Reply exactly OK. Do not use tools.' |
  opencode run --format json --dir [REPO_A] \
    --session [SAME_DIR_PARENT] --fork --model [PROVIDER/MODEL]

Cross-directory case — stalls with zero stdout and stderr:

printf '%s\n' 'Reply exactly OK. Do not use tools.' |
  opencode run --format json --dir [REPO_B] \
    --session [CROSS_DIR_PARENT] --fork --model [PROVIDER/MODEL]

An external 25–30 second timeout is needed to terminate the second command.

Observed controls

  • Fresh sessions complete in both /tmp and the source Git repository.
  • A one-shot fork that keeps the parent directory completes.
  • A one-shot fork from an equivalent parent into a different worktree stalls
    before its first event.
  • The cross-directory stall reproduces on both 1.17.11 and 1.18.25.
  • Adding or removing the caller's permission overlay does not change the result.
  • Adding or removing macOS sandbox-exec does not change the result.
  • Exporting/importing the parent with the worktree directory and resuming the
    imported session also stalled in the observed environment.

Expected behavior

The fork should preserve the parent context and launch in the requested
directory, or fail quickly with an actionable error if changing the child
directory is unsupported. It should not remain alive indefinitely with no
stdout or stderr.

Related issues

  • #31964 reports changed-cwd session state and permission routing problems
    through ACP.
  • #35870 reports intermittent headless startup hangs, especially for fresh
    directories.

This reproduction is narrower: opencode run --session ... --fork, sequential
processes, same Git repository, and same-directory versus sibling-worktree
controls.

Activity

  1. Great-Bucket commented on Aug 30, 2026

    @Great-Bucket
    Author

    Independent human-guided terminal confirmation on a second controlled run:

    Environment:

    • macOS 14.6.1 (23G93), Intel x86_64
    • OpenCode 1.17.11 at /usr/local/bin/opencode
    • Commands run sequentially
    • No CHATR-BUS process, permission overlay, or sandbox-exec
    • Two separate parent sessions, each forked exactly once
    • External Python subprocess timeout: 30 seconds

    Results:

    1. Fresh session started directly in detached worktree B: completed in 8.85 s,
      exit 0, one step_start, one text event, one step_finish, zero stderr.
    2. Fresh parent created in source directory A: completed in 10.28 s.
    3. Parent A forked with child also in A: completed in 9.46 s, exit 0, complete
      event sequence, and a distinct child session ID.
    4. Separate equivalent parent created in A: completed in 8.07 s.
    5. Parent A forked with child --dir changed to detached worktree B: timed out
      after 30.09 s with zero stdout bytes, zero stderr bytes, no events, and no
      child session ID.

    The worktree was then removed cleanly and no test OpenCode process remained.

    This supports the narrow same-directory-versus-cross-directory distinction in
    the issue. The test does not determine OpenCode's internal cause.

  2. Great-Bucket commented on Aug 30, 2026

    @Great-Bucket
    Author

    Follow-up: the combined CLI hang still reproduces, but OpenCode 1.18.25's
    experimental native workspace control plane provides a working alternative for
    the underlying use case.

    Validated sequence:

    1. Start an OpenCode 1.18.25 server with
      OPENCODE_EXPERIMENTAL_WORKSPACES=true, scoped to source directory A.
    2. Fork the parent through POST /session/:id/fork while still scoped to A.
    3. Register/discover existing Git worktree B with
      POST /experimental/workspace/sync-list.
    4. Warp only the child with POST /experimental/workspace/warp.
    5. Prompt the child normally; its workspace ID routes execution to B.
    6. Warp the child back with workspace ID null before workspace removal.

    Results on OpenCode 1.18.25:

    • existing detached worktree discovered;
    • distinct child created, parent unchanged;
    • child inherited parent context;
    • child Bash pwd and own writes operated in B;
    • under an outer macOS seatbelt profile, writes to source A, another worktree,
      /tmp, TMPDIR, and cache paths were denied;
    • child detached and remained resumable afterward; and
    • workspace row and Git worktree removed cleanly.

    This does not make the opencode run --session PARENT --fork --dir B stall
    expected: that command should still complete or fail explicitly. It does narrow
    the issue to the combined CLI path; OpenCode's native fork-then-warp workflow
    works for the session-in-worktree use case.

  3. MartinSchlott commented on Sep 19, 2026

    @MartinSchlott

    This is a concrete blocker for me, not just an edge case.

    The session’s stored working directory can become stale when the original directory is deleted, renamed, moved, or—as in my case—was a temporary directory created by the host application and no longer exists.

    Once session.directory points to a non-existing path, I can no longer resume or fork that session, even if I explicitly provide a valid directory:

    opencode run --session <session-id> --fork --dir <existing-directory>

    OpenCode still tries to resolve the stale stored directory and fails before the requested --dir can take effect.

    I verified that the session itself is otherwise intact: changing only its directory field in opencode.db to a valid path makes the same session resume successfully with its full history.

    So there is currently no supported recovery path for this situation. The session is effectively blocked unless the database is edited manually.

    An explicit --dir should either override the stale stored directory for the fork/resume, or OpenCode should provide another supported way to rebind the session to a valid directory.

  4. thdxr commented on Oct 11, 2026

    @thdxr
    Member

    Thanks for the report! OpenCode 2.0 is now out and development is focused on V2, so we're closing issues filed against OpenCode 1. Please upgrade (opencode upgrade --major, details: https://anoma.ly/notes/opencode-2-0), and if this is still relevant on 2.0, reopen this issue or open a new one with your 2.0 version.

    — from 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions