`codex app-server daemon` commands fail with `path must be shorter than SUN_LEN` when CODEX_HOME is a deep path (macOS)

Open 💬 6 comments Opened Jun 12, 2026 by Bohan-J

Summary

All codex app-server daemon client commands (version, start, stop, ...) derive the control socket path as $CODEX_HOME/app-server-control/app-server-control.sock. On macOS, the sun_path limit for Unix domain sockets is 104 bytes, so any CODEX_HOME longer than ~60 characters makes these commands fail before they can connect:

Error: failed to connect to <CODEX_HOME>/app-server-control/app-server-control.sock

Caused by:
    path must be shorter than SUN_LEN

There is currently no way to override the control socket location for the daemon client commands: codex app-server proxy accepts --sock, and the server side accepts --listen unix://PATH, but codex app-server daemon version/start/stop do not, and there is no config key or environment variable for it (the path is hardcoded in app_server_control_socket_path() in codex-rs/app-server-transport/src/transport/mod.rs).

Deep CODEX_HOME paths are common for tools that run Codex in isolated per-task or per-project homes (CI sandboxes, agent platforms, devcontainer setups), where the home lives inside a nested workspace directory and easily exceeds the budget.

Environment

  • macOS (Darwin 25.4.0, arm64)
  • codex-cli 0.137.0 (also reported on 0.139.0)

Reproduction

DEEP="/tmp/codex-sunlen-repro/$(printf 'a%.0s' {1..40})/$(printf 'b%.0s' {1..40})/codex-home"
mkdir -p "$DEEP"
echo "${#DEEP}"   # 116 chars
CODEX_HOME="$DEEP" codex app-server daemon version

Output:

Error: failed to connect to /private/tmp/codex-sunlen-repro/aaaa…aaaa/bbbb…bbbb/codex-home/app-server-control/app-server-control.sock

Caused by:
    path must be shorter than SUN_LEN

Note that pointing CODEX_HOME at a short symlink to the deep directory does not help: the home is canonicalized before the socket path is derived (visible above as /tmp resolving to /private/tmp), so the resolved long path still exceeds the limit.

Expected behavior

codex app-server daemon commands should work regardless of how deep CODEX_HOME is. Any of the following would solve it:

  1. An override for the control socket directory — a config key (e.g. app_server.control_socket_dir), an environment variable, or a --sock flag on the daemon subcommands (matching the existing codex app-server proxy --sock).
  2. A short hashed default location when the derived path would exceed the platform limit — e.g. $TMPDIR/codex-<hash-of-CODEX_HOME>/control.sock, similar to how OpenSSH solves the same problem with ControlPath %C.
  3. At minimum, a clearer error message that names CODEX_HOME length as the cause and suggests a workaround.

View original on GitHub ↗

6 Comments

wgu9 · 2 months ago

I checked current main and this still looks like a single choke point rather than a daemon-only bug.

The default control socket path is built in codex-rs/app-server-transport/src/transport/mod.rs:

pub fn app_server_control_socket_path(codex_home: &Path) -> std::io::Result<AbsolutePathBuf> {
    AbsolutePathBuf::from_absolute_path(
        codex_home
            .join(APP_SERVER_CONTROL_SOCKET_DIR_NAME)
            .join(APP_SERVER_CONTROL_SOCKET_FILE_NAME),
    )
}

That same helper is used by:

  • codex-rs/app-server-daemon/src/lib.rs in Daemon::from_environment() for lifecycle commands such as version, start, stop, etc.
  • AppServerTransport::from_listen_url("unix://"), so the default Unix listener path has the same long-CODEX_HOME exposure.
  • codex app-server proxy when --sock is omitted.
  • TUI/default daemon probing paths that try to discover the local app-server daemon.

So I would avoid fixing this only in the CLI command parser. A more robust fix would make app_server_control_socket_path() return a platform-safe path by default, or add a single resolver beside it that all default-control-socket callers use.

Patch shape that seems low-risk:

  1. Keep the current $CODEX_HOME/app-server-control/app-server-control.sock path while it is short enough.
  2. If the path exceeds the Unix-domain-socket budget, fall back to a short per-user temp/runtime path keyed by a hash of canonical CODEX_HOME, for example $TMPDIR/codex-app-server/<hash>/control.sock.
  3. Keep the startup/operation lock and pid/settings state under CODEX_HOME; only the UDS rendezvous path needs to move.
  4. Add coverage in codex-rs/app-server-transport/src/transport/unix_socket_tests.rs for a deep CODEX_HOME and for stable hashing, plus one daemon/client smoke test if the final API surface changes.

One small test detail: find_codex_home() canonicalizes CODEX_HOME, so the regression test should create the deep directory first and assert against the canonical path length. That matches the reported /tmp -> /private/tmp behavior on macOS.

kyoh86 · 2 months ago

I can reproduce the same failure on Ubuntu 24.04.4 LTS on WSL2.

Environment:

  • Codex CLI: codex-cli 0.142.2
  • OS: Ubuntu 24.04.4 LTS on WSL2
  • Kernel: 6.6.87.2-microsoft-standard-WSL2
  • WSL version: 2.6.3.0
  • Architecture: x86_64

In my case this shows up when CODEX_HOME is configured under an XDG-style config path and resolves to a long path. The symlink/dotfiles detail is only one way to hit the issue; the underlying problem is that runtime socket paths are derived from CODEX_HOME.

I also think it would be useful to separate the default location question from the override question:

  • Runtime IPC files such as Unix sockets, pid files, and locks should probably not live under CODEX_HOME by default.
  • On Linux, XDG_RUNTIME_DIR seems like a more appropriate default for runtime files.
  • However, XDG_RUNTIME_DIR can also be unsuitable in some environments, so a Codex-specific override such as CODEX_RUNTIME_DIR or CODEX_APP_SERVER_RUNTIME_DIR would still be valuable.

So the desired shape from my perspective would be:

  1. Keep durable Codex config/state under CODEX_HOME.
  2. Put app-server runtime files under a runtime directory by default, e.g. XDG_RUNTIME_DIR on Linux.
  3. Provide an explicit Codex-specific environment variable or config key for the runtime directory, so users can choose a short/suitable path when needed.
nezc · 1 month ago

I can reproduce this through Codex Desktop SSH to a Linux remote.

  • Codex App: 26.707.31428 (build 5059) on macOS 15.7.3
  • Remote CLI: codex-cli 0.144.1
  • Remote /root is a symlink to a deeply nested persistent-volume path
  • Canonical control-socket path: 130 bytes

SSH public-key authentication, the remote shell/version probes, and app-server bootstrap all succeed. The failure occurs when Desktop runs codex app-server proxy:

Error: failed to connect to socket at
/redacted/deep/path/.codex/app-server-control/app-server-control.sock

Caused by:
    path must be shorter than SUN_LEN

Desktop then surfaces only ECONNRESET: socket hang up, making this look like an SSH/network failure.

This confirms the same path-length bug also blocks the Desktop SSH flow. A short symlink does not help because CODEX_HOME is canonicalized; using a genuinely short real path/bind mount works around it.

tsuvic · 21 days ago

Still reproduces on current macOS builds (arm64), identically on both:

  • standalone CLI 0.146.0
  • ChatGPT desktop bundled codex 0.147.0-alpha.6.5
$ DEEP=/tmp/x/aaaa…(40)/bbbb…(40)/codex-home   # 116 chars
$ CODEX_HOME=$DEEP codex app-server daemon version
Error: failed to connect to /private/tmp/x/aaaa…/bbbb…/codex-home/app-server-control/app-server-control.sock

Caused by:
    path must be shorter than SUN_LEN

Including the /tmp → /private/tmp canonicalization that defeats short-symlink workarounds.

Update — traced to a single choke point on current main:

  • app_server_control_socket_path() (codex-rs/app-server-transport/src/transport/mod.rs:54–62) always returns CODEX_HOME/app-server-control/app-server-control.sock (+44 bytes), and find_codex_home() canonicalizes a CODEX_HOME env value (codex-rs/utils/home-dir/src/lib.rs:45), hence /private/tmp.
  • The error itself comes from Rust std (os/unix/net/addr.rs): macOS sun_path is 104 bytes, so the usable budget for CODEX_HOME is 103 − 44 = 59 bytes.
  • Everything (daemon bind/connect, TUI auto-connect, codex doctor, app-server proxy) funnels through that one function — which is also why doctor misreports "stale or unreachable" here.

The repo already solves this exact problem two other places: codex-rs/linux-sandbox/src/proxy_routing.rs:58 (UNIX_SOCKET_PATH_MAX_BYTES + /tmp fallback chain) and codex-rs/tui/src/ide_context/ipc.rs:179–190 ($TMPDIR/codex-ipc/… fallback + explicit sockaddr_un length checks). The control socket is the last unhandled site.

Suggested fix (hybrid, zero migration): keep the classic path when it fits (≤103 bytes — every currently working install); otherwise fall back to a deterministic short path both daemon and clients can compute with no I/O:

/tmp/codex-<uid>/<sha256(canonical CODEX_HOME)[:16]>/app-server-control.sock

(Linux: prefer $XDG_RUNTIME_DIR/codex; root dir verified uid-owned + 0700.) Collision safety can be hardened for free by checking InitializeResponse.codex_home on fallback probes. Deep-CODEX_HOME installs are fully broken today, so there is nothing to stay compatible with.

tsuvic · 9 days ago

Still reproduces on 0.148.0 (release binary, macOS arm64), identically to 0.137–0.147:

$ CODEX_HOME=/tmp/x/aaaa…(40)/bbbb…(40)/codex-home   # deep path
$ codex app-server daemon version
Error: failed to connect to /private/tmp/x/aaaa…/bbbb…/codex-home/app-server-control/app-server-control.sock

Caused by:
    path must be shorter than SUN_LEN

Including the /tmp → /private/tmp canonicalization (+8 bytes) that defeats short-symlink workarounds.

On current main the single choke point is unchanged: app_server_control_socket_path() (codex-rs/app-server-transport/src/transport/mod.rs:58–64) still has no length handling, and every producer/consumer (daemon bind/connect, TUI auto-connect, codex doctor, app-server proxy) funnels through it. The hybrid fallback suggested in my earlier comment (keep the classic path when ≤103 bytes, otherwise a deterministic hashed short path both sides can compute without I/O) still applies; the in-tree templates for exactly this remain codex-rs/linux-sandbox/src/proxy_routing.rs and codex-rs/tui/src/ide_context/ipc.rs.

tlatjdgh3778 · 2 days ago

I can confirm that this still reproduces on Codex CLI 0.149.1 when launched through Orca, which uses an isolated per-account CODEX_HOME.

### Environment

  • macOS 26.5.2 (Build 25F84), arm64
  • Orca 1.4.184
  • Codex CLI 0.149.1
  • CODEX_HOME length: 108 bytes
  • Derived control socket path length: 151 bytes

The generated path has this form:

```text
/Users/<user>/Library/Application Support/orca/codex-accounts/<account-id>/home/app-server-control/app-server-control.sock

Starting a normal Codex session through Orca produces:

Failed to start the background server: Error: app server did not become ready on <CODEX_HOME>/app-server-control/app-server-control.sock

Managed app-server stderr:
Error: path must be shorter than SUN_LEN

Caused by:
0: failed to connect to <CODEX_HOME>/app-server-control/app-server-control.sock
1: path must be shorter than SUN_LEN

The managed app-server binary is:

Codex CLI 0.149.1

codex doctor --json reports that the background server is not running, while the installation, configuration, authentication, and provider reachability checks all pass.

This is worth noting because the deep path is not an unusual project path configured manually. It is the default per-account home layout generated by Orca under macOS Application
Support. This means GUI or integration hosts that isolate Codex accounts can exceed the socket-path limit by default.

There is no existing control socket, and restarting only reproduces the same bind/connect failure. This confirms that the issue remains present in 0.149.1.