claude-code icon indicating copy to clipboard operation
claude-code copied to clipboard

[BUG] Sandbox file watcher crashes when watching Unix socket files (ENXIO/EOPNOTSUPP)

Open dongruixiao opened this issue 3 weeks ago • 1 comments

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

Description

When using the Claude Agent SDK with sandbox enabled, the CLI crashes with ENXIO or EOPNOTSUPP errors because the file watcher attempts to watch Unix socket files, which is not supported by Node.js/Bun's fs.watch().

Environment

  • OS: macOS (Darwin 25.1.0) and Linux (Fly.io)
  • Runtime: Bun v1.3.4
  • Claude Agent SDK: Python SDK (latest)

Steps to Reproduce

from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions, SandboxSettings

client = ClaudeSDKClient(
    options=ClaudeAgentOptions(
        settings="{}",
        sandbox=SandboxSettings(
            enabled=True,
            autoAllowBashIfSandboxed=True,
            allowUnsandboxedCommands=False,
        ),
    ),
)

Error on macOS

Error: EOPNOTSUPP: unknown error, watch '/var/folders/vn/.../T/vscode-git-76f5dfb970.sock'
    at watch (unknown)
    at new FSWatcher (node:fs:29:31)
    at watch (node:fs:296:23)
    at l8_ (/$bunfs/root/claude:352:6174)

Error on Linux

ENXIO: no such device or address, watch '/tmp/claude-http-1efa533c677af13a.sock'
    path: "/tmp/claude-http-1efa533c677af13a.sock",
    syscall: "watch",
    errno: -6,
    code: "ENXIO"
    at new FSWatcher (node:fs:30:31)
    at watch (node:fs:300:10)
    at k8I (/$bunfs/root/claude:349:6174)

On Linux, the CLI is trying to watch its own socket files (claude-http-*.sock, claude-socks-*.sock) that it creates for internal communication.

Root Cause

fs.watch() does not support watching Unix socket files (special file type). When the sandbox file watcher scans /tmp/ or /var/folders/.../T/, it encounters .sock files and crashes.

Suggested Fix

1. Filter out socket files (.sock) before calling fs.watch()
2. Or wrap fs.watch() calls in try-catch to handle unsupported file types gracefully
3. Or check file type with fs.stat() before watching

Example fix:
const stats = fs.statSync(path);
if (stats.isSocket()) {
    return; // Skip socket files
}
fs.watch(path, options, callback);

Workaround

Disable sandbox or don't pass sandbox/settings parameters:
client = ClaudeSDKClient(
    options=ClaudeAgentOptions(),  # No sandbox settings
)

### What Should Happen?

no ENXIO error

### Error Messages/Logs

```shell
2025-12-23T07:20:16Z app[e829429c717478] lhr [info]ENXIO: no such device or address, watch '/tmp/claude-http-1efa533c677af13a.sock'
2025-12-23T07:20:16Z app[e829429c717478] lhr [info]     path: "/tmp/claude-http-1efa533c677af13a.sock",
2025-12-23T07:20:16Z app[e829429c717478] lhr [info]  syscall: "watch",
2025-12-23T07:20:16Z app[e829429c717478] lhr [info]    errno: -6,
2025-12-23T07:20:16Z app[e829429c717478] lhr [info] filename: "/tmp/claude-http-1efa533c677af13a.sock",
2025-12-23T07:20:16Z app[e829429c717478] lhr [info]     code: "ENXIO"
2025-12-23T07:20:16Z app[e829429c717478] lhr [info]      at new FSWatcher (node:fs:30:31)
2025-12-23T07:20:16Z app[e829429c717478] lhr [info]      at watch (node:fs:300:10)
2025-12-23T07:20:16Z app[e829429c717478] lhr [info]      at k8I (/$bunfs/root/claude:349:6174)
2025-12-23T07:20:16Z app[e829429c717478] lhr [info]      at JR0 (/$bunfs/root/claude:349:11387)
2025-12-23T07:20:16Z app[e829429c717478] lhr [info]      at _watchWithNodeFs (/$bunfs/root/claude:349:6655)
2025-12-23T07:20:16Z app[e829429c717478] lhr [info]      at _handleFile (/$bunfs/root/claude:349:7398)
2025-12-23T07:20:16Z app[e829429c717478] lhr [info]      at _addToNodeFs (/$bunfs/root/claude:349:10425)
2025-12-23T07:20:16Z app[e829429c717478] lhr [info]25 |       options = { encoding: options };
2025-12-23T07:20:16Z app[e829429c717478] lhr [info]26 |     if (typeof listener !== "function")
2025-12-23T07:20:16Z app[e829429c717478] lhr [info]27 |       listener = () => {
2025-12-23T07:20:16Z app[e829429c717478] lhr [info]28 |       };
2025-12-23T07:20:16Z app[e829429c717478] lhr [info]29 |     this.#listener = listener;
2025-12-23T07:20:16Z app[e829429c717478] lhr [info]30 |       this.#watcher = fs.watch(path, options || {}, this.#onEvent.bind(this));

Steps to Reproduce

import asyncio
import json
from claude_agent_sdk import query, ClaudeAgentOptions, SandboxSettings, ClaudeSDKClient


async def main():
    client = ClaudeSDKClient(
        options=ClaudeAgentOptions(
            settings=json.dumps({}),
            sandbox=SandboxSettings(
               **{
                   "enabled": True,
                   "autoAllowBashIfSandboxed": True,
                   "allowUnsandboxedCommands": False,
               }
           ),
        ),
    )
    async with client as cli:
        await cli.query("hi")

        async for message in cli.receive_response():
            print(message)

Claude Model

Opus

Is this a regression?

Yes, this worked in a previous version

Last Working Version

v0.1.18

Claude Code Version

2.0.75 (Claude Code)

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

iTerm2

Additional Information

No response

dongruixiao avatar Dec 23 '25 07:12 dongruixiao