{"record":{"id":"395a48085da8370d","repo":"JuliusBrussee/caveman","slug":"native-session-key-length-d-want-d","errorCode":null,"errorMessage":"native session key length = %d, want %d","messagePattern":"native session key length = (.+?), want (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"proxy/internal/nativeruntime/marker.go","lineNumber":61,"sourceCode":"\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}\n\t\tif closeErr := file.Close(); closeErr != nil {\n\t\t\treturn nil, fmt.Errorf(\"native session key close: %w\", closeErr)\n\t\t}\n\t\treturn key, nil\n\t}\n\tif !errors.Is(err, os.ErrExist) {\n\t\treturn nil, fmt.Errorf(\"native session key create: %w\", err)\n\t}\n\tkey, err = os.ReadFile(path)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"native session key read: %w\", err)\n\t}\n\tif len(key) != sessionKeyBytes {\n\t\treturn nil, fmt.Errorf(\"native session key length = %d, want %d\", len(key), sessionKeyBytes)\n\t}\n\tif err := os.Chmod(path, 0o600); err != nil {\n\t\treturn nil, fmt.Errorf(\"native session key chmod: %w\", err)\n\t}\n\treturn key, nil\n}\n\n// SessionMarker builds model-temporary correlation context. Local proxy removes\n// valid markers byte-surgically before provider inspection or forwarding.\nfunc SessionMarker(key []byte, sessionID string) (string, error) {\n\tif len(key) != sessionKeyBytes || sessionID == \"\" || len(sessionID) > 256 {\n\t\treturn \"\", errors.New(\"native session marker: invalid key or session id\")\n\t}\n\tencoded := base64.RawURLEncoding.EncodeToString([]byte(sessionID))\n\tsig := markerMAC(key, encoded)\n\treturn fmt.Sprintf(`[[caveman-session-v1 sid=\"%s\" sig=\"%s\"]]`, encoded, sig), nil\n}\n","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/766dce6b1394ebb56a3090748d5a0240a5aefb36/proxy/internal/nativeruntime/marker.go#L43-L79","documentation":"An existing session.key does not contain exactly 32 bytes, so it cannot be the HMAC key this runtime writes; the message reports both the actual and expected lengths. The size mismatch means the file was created or altered by something other than this code: manual editing, a truncated copy or restore, a different tool version's format, or an empty file from touch. The runtime refuses to guess rather than silently change the MAC domain.","triggerScenarios":"A user wrote text into session.key (echo mysecret > session.key); a backup/restore or rsync truncated the file; another tool version wrote a different key size; touch session.key created a 0-byte placeholder.","commonSituations":"Operators 'setting a key' by hand; partial home-directory syncs via git or cloud drives; mixed-version installs sharing one home.","solutions":["If no session markers need to survive: rm <home>/runtime/session.key and restart — a fresh key is minted and old signed markers become inert text","If you have the correct key material, restore exactly 32 bytes (re-copy the original file, do not retype it)","Verify: wc -c <home>/runtime/session.key must print 32","Audit what wrote the file (shell history, sync tools) so it does not recur"],"exampleFix":"# before\n$ wc -c ~/.caveman/runtime/session.key\n12\n$ caveman start\nerror: native session key length = 12, want 32\n\n# after\n$ rm ~/.caveman/runtime/session.key\n$ caveman start   # mints a fresh 32-byte key\nok","handlingStrategy":"validation","validationCode":"keyPath := filepath.Join(home, \"runtime\", \"session.key\")\nif info, err := os.Stat(keyPath); err == nil && info.Size() != 32 {\n\treturn fmt.Errorf(\"session.key is %d bytes (want 32) — remove %s to mint a fresh key (old markers become inert)\", info.Size(), keyPath)\n}\n// safe to call nativeruntime.LoadOrCreateSessionKey(home)","typeGuard":null,"tryCatchPattern":"key, err := nativeruntime.LoadOrCreateSessionKey(home)\nif err != nil {\n\tif strings.HasPrefix(err.Error(), \"native session key length\") {\n\t\t// file was hand-edited, truncated, or written by another tool —\n\t\t// guided recovery instead of a raw failure:\n\t\tlog.Printf(\"remove %s and restart to mint a new key; session markers signed with the old key will no longer correlate\", filepath.Join(home, \"runtime\", \"session.key\"))\n\t}\n\treturn err\n}","preventionTips":["Never hand-edit or 'set' session.key — the key is machine-generated binary, exactly 32 bytes","Exclude <home>/runtime from git/cloud-drive sync of the home directory","After restoring homes from backup, verify wc -c session.key == 32 before starting","Do not share one home between different product versions that may use different key formats"],"tags":["go","configuration","data-corruption","filesystem"],"backgroundTag":"corrupt-key-file","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"}