Skip to content

cli(v2): positional directory resolved locally even with --server, fails on remote-only paths #47665

Open

Description

@OleksandrRakovets

Summary

opencode2 <directory> --server <url> fails with a local ENOENT chdir when the directory only exists on the remote server. The CLI resolves the positional directory locally before considering --server, instead of passing it through as the remote location.

Environment

  • opencode version: v0.0.0-beta-19192
  • OS: macOS 26.6.2 client -> Linux server (6.8.0-139-generic, x86_64)
  • Terminal: Ghostty 1.3.1
  • Shell: Unavailable (not provided)
  • Install/channel: beta
  • Active plugins: none found in config

Reproduction

  1. On the Linux server, have a project at /home/sasha/ks and start the server (opencode2 serve, reachable over tailscale).
  2. On the macOS client, run either order:
    • opencode2 "/home/sasha/ks" --server https://<server>
    • opencode2 --server https://<server> "/home/sasha/ks"
  3. Observe immediate failure before any connection:
    ERROR: ENOENT: no such file or directory, chdir '...' -> '/home/sasha/ks'

Expected Behavior

With --server, the positional directory should be sent to the server and resolved server-side as the session location (no local chdir).

Actual Behavior

Both argument orders crash locally in process.chdir() because /home/sasha/ks does not exist on the Mac. V1 had the same class of bug (attach --dir, #5380/#8933/#8981/#11896); V2 reintroduces it via the positional directory argument.

Additional Context

  • packages/cli/src/commands/handlers/default.ts:19 (branch v2): if (requestedDirectory !== undefined) process.chdir(requestedDirectory) runs unconditionally, ignoring requestedServer.
  • packages/tui/src/app.tsx:212 then uses process.cwd() as location.directory, so even a successful local chdir would send the local path.
  • Server side (packages/server/src/location.ts, requestRef) already supports receiving the directory via location[directory] query / x-opencode-directory header and falls back to server cwd — the client just never gets that far.
  • Consistently reproducible. Workaround: connect bare (opencode2 --server <url>, lands in server cwd) or pre-create the session server-side and attach with --session <id> --continue.

Activity

  1. Rocklis commented on Sep 7, 2026

    @Rocklis

    Opened #47818 for this. The CLI now leaves the remote directory alone and sends it through to the initial location request; skipping chdir without that second change still sent the client's cwd.

    Both argument orders and a relative remote path pass the CLI regression tests. Those use a local HTTP fixture, so if you have a chance to try the branch with your Mac-to-Linux setup, that would be useful.

  2. OleksandrRakovets commented on Sep 9, 2026

    @OleksandrRakovets
    Author

    @Rocklis I have no doubts the patch would work for this case.

    We need to the direction from the team on how do they see this interface. Possibly, the fix would lie in a different layer.

  3. Rocklis commented on Sep 9, 2026

    @Rocklis

    The current patch keeps the change at the CLI/TUI boundary: it leaves the local cwd alone and passes the requested directory to the existing location API. It doesn't change the server API.

    @jlongster Should the positional directory with --server select a remote project, or do you want that selection handled elsewhere? I can adjust #47818 once that direction is clear.

  4. TrevorMashilo commented on Oct 17, 2026

    @TrevorMashilo

    session ID: ses_ee835f167ffez5vlFaisjbTH30 Zen log ID fb4db517-4a5d-4a70-b896-7c08bf74831e, and “same error, desktop 1.19.3, Windows, started Oct 17

  5. opencodejr commented on Oct 28, 2026

    @opencodejr

    Thanks for the detailed report. I reproduced this on @opencode/cli@2.2.0 (your beta build isn't published on npm, so I used the latest release), and it still happens on the latest dev (b6c43a52).

    Steps:

    1. Start opencode serve in one project directory.
    2. From another directory, run opencode <dir> --server <url> and opencode --server <url> <dir>, where <dir> doesn't exist on the client.

    Both orders fail immediately with ENOENT: no such file or directory, chdir '...' -> '<dir>'. The same error appears when --server points to a port where nothing is listening, which shows the CLI changes into the directory locally before it ever connects. The script below reproduces it.

    Related: #47818, an earlier PR that targeted this issue and was closed without being merged; #49663, the same raw ENOENT chdir error for a missing local directory; and #5380, the v1 attach --dir version of this problem.

    Reproduction script (repro.sh)
    #!/usr/bin/env bash
    # Reproduces #47665: `opencode <dir> --server <url>` chdirs into <dir> locally
    # before connecting, so a directory that only exists on the server fails.
    # Usage: ./repro.sh            -> uses `opencode` from PATH
    #        OC_DEV=/path/to/repo ./repro.sh -> runs the CLI from a source checkout
    set -u
    if [ -n "${OC_DEV:-}" ]; then
      OC=(bun --conditions=browser --preload="$OC_DEV/packages/tui/node_modules/@opentui/solid/scripts/preload.js" "$OC_DEV/packages/cli/src/index.ts")
    else
      OC=(opencode)
    fi
    echo "version: $("${OC[@]}" --version)"
    
    REMOTE_ONLY=/home/remote-user/project-only-on-server   # does not exist on this (client) machine
    test -e "$REMOTE_ONLY" && { echo "path unexpectedly exists locally"; exit 1; }
    
    # Start a "remote" server (here on localhost, from its own project dir).
    WORK=$(mktemp -d); mkdir -p "$WORK/server-project"
    ( cd "$WORK/server-project" && "${OC[@]}" serve --hostname 127.0.0.1 --port 4598 >"$WORK/server.log" 2>&1 ) &
    SRV=$!
    trap 'kill $SRV 2>/dev/null' EXIT
    for i in $(seq 1 60); do grep -q "listening" "$WORK/server.log" 2>/dev/null && break; sleep 0.5; done
    cat "$WORK/server.log" | head -1
    
    cd "$WORK"
    echo; echo "== order 1: <dir> --server <url>"
    timeout 20 "${OC[@]}" "$REMOTE_ONLY" --server http://127.0.0.1:4598 </dev/null 2>&1 | head -5
    echo; echo "== order 2: --server <url> <dir>"
    timeout 20 "${OC[@]}" --server http://127.0.0.1:4598 "$REMOTE_ONLY" </dev/null 2>&1 | head -5
    echo; echo "== same with a server URL where nothing listens (shows the failure happens before any connection)"
    timeout 20 "${OC[@]}" "$REMOTE_ONLY" --server http://127.0.0.1:1 </dev/null 2>&1 | head -5

    Run it: bash repro.sh

  6. andycostintoma commented on Nov 5, 2026

    @andycostintoma

    +1 from my report (#62072). Cross-host, the positional argument can't work by construction: our client and server run on different machines with different home layouts, so no absolute path exists on both ends — client-side resolution gives ENOENT, server-side resolution of the client's cwd gives "Location not found". For that case we'd get more mileage from an explicit option (--location, or a settable /api/location) than from redefining the positional argument — they compose with client-side cwd discovery rather than competing with it.

    Workaround we shipped meanwhile: POST /api/session with location.directory, then launch the TUI with -s <id>. Happy to drop that dance once #47818 lands in whatever shape.

  7. Rocklis commented on Nov 7, 2026

    @Rocklis

    Thanks for the additional reports. I can pick #47818 back up; it was closed by the cleanup bot. The earlier branch also has a cross-machine end-to-end check from @kernel-oops: #47818 (comment)

    @jlongster Would you prefer the positional directory with --server to select the remote project, as that patch does, or an explicit option such as --location, as suggested above? I can update the patch once that is settled. If the existing approach fits, could you reopen #47818 so I can bring it up to date?

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions