JuliusBrussee/caveman · error
native session key length = %d, want %d
Error message
native session key length = %d, want %d
What it means
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.
Source
Thrown at proxy/internal/nativeruntime/marker.go:61
if syncErr := file.Sync(); syncErr != nil {
_ = file.Close()
_ = os.Remove(path)
return nil, fmt.Errorf("native session key sync: %w", syncErr)
}
if closeErr := file.Close(); closeErr != nil {
return nil, fmt.Errorf("native session key close: %w", closeErr)
}
return key, nil
}
if !errors.Is(err, os.ErrExist) {
return nil, fmt.Errorf("native session key create: %w", err)
}
key, err = os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("native session key read: %w", err)
}
if len(key) != sessionKeyBytes {
return nil, fmt.Errorf("native session key length = %d, want %d", len(key), sessionKeyBytes)
}
if err := os.Chmod(path, 0o600); err != nil {
return nil, fmt.Errorf("native session key chmod: %w", err)
}
return key, nil
}
// SessionMarker builds model-temporary correlation context. Local proxy removes
// valid markers byte-surgically before provider inspection or forwarding.
func SessionMarker(key []byte, sessionID string) (string, error) {
if len(key) != sessionKeyBytes || sessionID == "" || len(sessionID) > 256 {
return "", errors.New("native session marker: invalid key or session id")
}
encoded := base64.RawURLEncoding.EncodeToString([]byte(sessionID))
sig := markerMAC(key, encoded)
return fmt.Sprintf(`[[caveman-session-v1 sid="%s" sig="%s"]]`, encoded, sig), nil
}
View on GitHub (pinned to 27d5a3981a)
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
Example fix
# before $ wc -c ~/.caveman/runtime/session.key 33 # trailing newline -> Error[1074] # after $ rm ~/.caveman/runtime/session.key # regenerated as exactly 32 bytes on next start
Defensive patterns
Strategy: validation
Validate before calling
func keyFileSane(path string) bool {
fi, err := os.Stat(path)
return err == nil && fi.Mode().IsRegular() && fi.Size() == 32
}
kp := filepath.Join(home, "runtime", "session.key")
if !keyFileSane(kp) { /* regenerate deliberately, knowing old markers die */ } Prevention
- 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
When it happens
Trigger: 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.
Common situations: Operators provisioning keys with echo/printf which add '\n'; earlier disk-full incidents; configuration-management tools overwriting the file.
Related errors
- native session key mkdir: %w
- native session key chmod dir: %w
- native session key write: %w
- native session key sync: %w
- native session key close: %w
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/395a48085da8370d.
Report an issue: GitHub.