{"record":{"id":"a6b950d092a61638","repo":"JuliusBrussee/caveman","slug":"native-session-key-chmod-dir-w","errorCode":null,"errorMessage":"native session key chmod dir: %w","messagePattern":"native session key chmod dir: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"proxy/internal/nativeruntime/marker.go","lineNumber":29,"sourceCode":"\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"regexp\"\n)\n\nconst sessionKeyBytes = 32\n\nvar markerPattern = regexp.MustCompile(`\\[\\[caveman-session-v1 sid=\"([A-Za-z0-9_-]{1,384})\" sig=\"([0-9a-f]{64})\"\\]\\]`)\n\n// LoadOrCreateSessionKey returns one user-only HMAC key shared by CLI adapters\n// and local proxy. O_EXCL makes concurrent first startup converge on one key.\nfunc LoadOrCreateSessionKey(home string) ([]byte, error) {\n\tdir := filepath.Join(home, \"runtime\")\n\tif err := os.MkdirAll(dir, 0o700); err != nil {\n\t\treturn nil, fmt.Errorf(\"native session key mkdir: %w\", err)\n\t}\n\tif err := os.Chmod(dir, 0o700); err != nil {\n\t\treturn nil, fmt.Errorf(\"native session key chmod dir: %w\", err)\n\t}\n\tpath := filepath.Join(dir, \"session.key\")\n\tkey := make([]byte, sessionKeyBytes)\n\tif _, err := rand.Read(key); err != nil {\n\t\treturn nil, fmt.Errorf(\"native session key random: %w\", err)\n\t}\n\tfile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0o600)\n\tif err == nil {\n\t\tif _, writeErr := file.Write(key); writeErr != nil {\n\t\t\t_ = file.Close()\n\t\t\t_ = os.Remove(path)\n\t\t\treturn nil, fmt.Errorf(\"native session key write: %w\", writeErr)\n\t\t}\n\t\tif syncErr := file.Sync(); syncErr != nil {\n\t\t\t_ = file.Close()\n\t\t\t_ = os.Remove(path)\n\t\t\treturn nil, fmt.Errorf(\"native session key sync: %w\", syncErr)\n\t\t}","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/766dce6b1394ebb56a3090748d5a0240a5aefb36/proxy/internal/nativeruntime/marker.go#L11-L47","documentation":"LoadOrCreateSessionKey re-chmods the runtime directory to 0700 right after creating it; this error means that chmod failed even though MkdirAll just succeeded. In practice the directory was removed or replaced between the two calls, is owned by another uid, or sits on a mount without usable POSIX chmod semantics (NFS, FUSE, vfat/exFAT). The 0700 mode is a hard requirement because the directory guards the shared HMAC session key.","triggerScenarios":"Concurrent first startup where another process deletes/recreates <home>/runtime between MkdirAll and Chmod; the runtime dir was left root-owned by an earlier sudo run; home on an NFS/SMB/FUSE mount where chmod on directories errors or is denied.","commonSituations":"Two CLI adapters or the local proxy launched simultaneously; mixed sudo/non-sudo usage of the same home; corporate network home directories; external exFAT drives used as CAVEMAN_HOME.","solutions":["Check ownership of <home>/runtime and chown it to the current user","Re-run the command — a concurrent-swap race usually does not repeat","Move CAVEMAN_HOME off network/exotic filesystems onto a native local FS","Delete <home>/runtime entirely and let the next start recreate it with correct modes"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if _, err := nativeruntime.LoadOrCreateSessionKey(home); err != nil {\n\tif errors.Is(err, fs.ErrPermission) && strings.Contains(err.Error(), \"chmod dir\") {\n\t\t// <home>/runtime is foreign-owned or on a chmod-hostile mount — repair ownership or move CAVEMAN_HOME, do not blind-retry\n\t\tlog.Printf(\"repair: sudo chown -R %d:%d %s or relocate home off NFS/FUSE\", os.Getuid(), os.Getgid(), home)\n\t}\n\treturn err\n}","preventionTips":["Keep CAVEMAN_HOME on a native local filesystem — NFS/FUSE/exFAT mounts reject or ignore directory chmod","Serialize first startups so no concurrent process swaps the runtime directory mid-call","Avoid mixed sudo/user usage of the same home","If a startup fails here more than once, delete <home>/runtime and let the next run rebuild it"],"tags":["go","filesystem","permissions","race-condition"],"backgroundTag":"chmod-permission-denied","analyzedSha":"766dce6b1394ebb56a3090748d5a0240a5aefb36","analyzedAt":"2026-08-18T03:14:35.516Z","contentChangedAt":"2026-08-18T03:14:35.516Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}