{"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":"console","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/27d5a3981a347890211bb1bf2439e5c821a63bc9/proxy/internal/nativeruntime/marker.go#L43-L79","documentation":"The existing session.key was read but its length is not the expected 32 bytes (sessionKeyBytes). The file was truncated, appended to, or hand-edited. Because HMAC markers minted with a wrong-length key would not match the markerPattern/signature contract, the mismatch is fatal rather than self-healed — regenerating would silently invalidate all in-flight markers.","triggerScenarios":"session.key is 0 bytes (truncated by disk-full during an old write), 33+ bytes (accidental append, echo adding a newline), or replaced by a text file; key written by a tool that appended a trailing newline.","commonSituations":"Operators provisioning keys with echo/printf which add '\\n'; earlier disk-full incidents; configuration-management tools overwriting the file.","solutions":["Remove the bad file (rm <home>/runtime/session.key) so the next start generates a fresh 32-byte key — note active session markers signed with the old key become invalid","Write keys byte-exact if provisioning externally: printf '%s' or dd, never echo","Confirm the file is exactly 32 bytes: wc -c <home>/runtime/session.key"],"exampleFix":"# before\n$ wc -c ~/.caveman/runtime/session.key\n33   # trailing newline -> Error[1074]\n\n# after\n$ rm ~/.caveman/runtime/session.key   # regenerated as exactly 32 bytes on next start","handlingStrategy":"validation","validationCode":"func keyFileSane(path string) bool {\n    fi, err := os.Stat(path)\n    return err == nil && fi.Mode().IsRegular() && fi.Size() == 32\n}\n\nkp := filepath.Join(home, \"runtime\", \"session.key\")\nif !keyFileSane(kp) { /* regenerate deliberately, knowing old markers die */ }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Provision keys byte-exactly (dd/printf '%s'), never echo (adds newline)","Health-check the key length in startup probes","Removing the key invalidates in-flight markers — do it in a quiet window"],"tags":["session-key","validation","filesystem","nativeruntime"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}