{"record":{"id":"15a6e596400e3c9d","repo":"JuliusBrussee/caveman","slug":"native-runtime-chmod-dir-w","errorCode":null,"errorMessage":"native runtime chmod dir: %w","messagePattern":"native runtime chmod dir: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"proxy/internal/nativeruntime/server_unix.go","lineNumber":40,"sourceCode":"}\n\n// Serve binds runtime transport for current platform.\nfunc Serve(ctx context.Context, home string, runtime *Runtime) error {\n\treturn ServeUnix(ctx, SocketPath(home), runtime)\n}\n\n// ServeUnix exposes one-request-per-connection JSON over a user-only Unix\n// socket. Runtime errors close or fail-open the individual call; they never stop\n// the coding agent or the provider proxy.\nfunc ServeUnix(ctx context.Context, path string, runtime *Runtime) error {\n\tif runtime == nil || runtime.store == nil {\n\t\treturn errors.New(\"native runtime: store is required\")\n\t}\n\tif err := os.MkdirAll(filepath.Dir(path), 0o700); err != nil {\n\t\treturn fmt.Errorf(\"native runtime mkdir: %w\", err)\n\t}\n\tif err := os.Chmod(filepath.Dir(path), 0o700); err != nil {\n\t\treturn fmt.Errorf(\"native runtime chmod dir: %w\", err)\n\t}\n\tif _, err := os.Stat(path); err == nil {\n\t\tconn, dialErr := net.DialTimeout(\"unix\", path, 50*time.Millisecond)\n\t\tif dialErr == nil {\n\t\t\t_ = conn.Close()\n\t\t\treturn errors.New(\"native runtime: socket already active\")\n\t\t}\n\t\tif err := os.Remove(path); err != nil {\n\t\t\treturn fmt.Errorf(\"native runtime remove stale socket: %w\", err)\n\t\t}\n\t} else if !os.IsNotExist(err) {\n\t\treturn fmt.Errorf(\"native runtime inspect socket: %w\", err)\n\t}\n\tlistener, err := net.Listen(\"unix\", path)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"native runtime listen: %w\", err)\n\t}\n\tdefer listener.Close()","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/proxy/internal/nativeruntime/server_unix.go#L22-L58","documentation":"ServeUnix enforces 0700 on the socket's parent directory after creating it, because the socket itself carries no other access control until it is chmod'd — a group/world-readable directory would let other local users connect to the runtime. Chmod failure means wrong ownership or a filesystem that does not support mode changes.","triggerScenarios":"Socket dir pre-created by root while the runtime runs unprivileged; directory on FAT/CIFS or other chmod-ignoring filesystem.","commonSituations":"Installers creating dirs as root; shared or foreign-mounted volumes.","solutions":["chown the socket directory to the runtime user and chmod 700 manually","Delete the pre-existing directory so ServeUnix recreates it as the running user","Use a local POSIX filesystem for the socket directory"],"exampleFix":"# before\nsudo mkdir -p /run/caveman   # owned by root -> Error[1077]\n\n# after\nsudo chown caveman:caveman /run/caveman && sudo chmod 700 /run/caveman","handlingStrategy":"validation","validationCode":"func socketDirTight(p string) bool {\n    fi, err := os.Stat(filepath.Dir(p))\n    return err == nil && fi.IsDir() && fi.Mode().Perm() == 0o700\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Systemd units: RuntimeDirectory=caveman with RuntimeDirectoryMode=0700","Do not pre-create the dir as root for an unprivileged service","Keep sockets off chmod-ignoring filesystems"],"tags":["unix-socket","permissions","security","nativeruntime"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}