Skip to content

fix: create socket dir before spawning session daemon - #1

Merged
ccakes merged 1 commit into
mainfrom
fix/session-daemon-socket-dir
Jul 7, 2026
Merged

ccakes merged 1 commit into
mainfrom
fix/session-daemon-socket-dir

Conversation

@ccakes

@ccakes ccakes commented Jul 7, 2026

Copy link
Copy Markdown
Owner

Problem

Starting a session fails on a clean /tmp with:

error: spawning session daemon: open /tmp/bench-<uid>/bench-<hash>.log: no such file or directory

The launcher (ensureSession) writes the detached daemon's .log into the per-user socket directory /tmp/bench-<uid>/ before spawning the daemon — but that directory is only created later by the daemon itself (Server.Start → EnsureSocketDir) when it binds its socket. macOS reaps /tmp entries after ~3 days, so a directory from a prior session is gone by the next launch and the log open (os.OpenFile with O_CREATE, which does not create parents) fails with ENOENT.

Regression from the detachable-sessions feature in 0.6.9.

Fix

ensureSession now calls api.EnsureSocketDir(sockPath) right before opening the log file, reusing the existing 0700 + symlink hardening the daemon already applies. The call is idempotent with the daemon's own, so the daemon path is unchanged.

ensurePrivateSocketDir is exported as EnsureSocketDir so the cli package can call it.

Tests

internal/api/socketdir_test.go (drives os.TempDir() via TMPDIR):

  • creates the private dir when missing, asserts 0700, and is idempotent
  • no-op for socket paths outside the private dir
  • rejects a symlinked private dir

Verification

Built a binary from the pre-fix cli.go and reproduced the exact error on a clean slate; the fixed binary starts cleanly and creates the dir (drwx------) containing both the .log (0600) and .sock. gofmt -l, go vet ./..., golangci-lint run, and go test ./... all clean.

Note for reviewers

EnsureSocketDir is intentionally a no-op for custom --socket/BENCH_SOCKET paths outside the private dir, so a custom socket in a nonexistent directory would still hit the same log-open failure. Left as-is: that path is user-chosen and net.Listen would surface a clear error there anyway. Happy to widen it if you'd prefer.

🤖 Generated with Claude Code

The launcher writes the detached daemon's log file into the per-user
socket directory (/tmp/bench-<uid>/) before spawning the daemon, but
that directory was only created later by the daemon itself when binding
its socket. On a clean /tmp (macOS reaps entries after ~3 days), opening
the log failed and the session never started:

    error: spawning session daemon: open /tmp/bench-<uid>/bench-*.log: no such file or directory

ensureSession now calls api.EnsureSocketDir before opening the log,
reusing the same 0700 + symlink hardening the daemon applies when it
binds. The call is idempotent with the daemon's own, so the daemon path
is unchanged. ensurePrivateSocketDir is exported as EnsureSocketDir for
reuse from the cli package.

Note: EnsureSocketDir is a no-op for custom --socket/BENCH_SOCKET paths
outside the private dir, so a custom socket in a nonexistent directory
would still fail the same way; left as-is since that path is user-chosen
and net.Listen would surface a clear error there anyway.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ccakes
ccakes force-pushed the fix/session-daemon-socket-dir branch from ab4cc16 to 54e616d Compare July 7, 2026 02:28
@ccakes
ccakes merged commit b3a05c0 into main Jul 7, 2026
4 checks passed
@ccakes
ccakes deleted the fix/session-daemon-socket-dir branch July 7, 2026 02:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant