JuliusBrussee/caveman · error
native runtime: unknown policy mode
Error message
native runtime: unknown policy mode %q
What it means
Handle validates request.PolicyMode after defaulting an empty value to "safe". Only "record", "safe", and "max" are accepted; any other string is rejected with this error. This keeps policy selection restricted to the supported profiles.
Solutions
- Set PolicyMode to one of exactly "record", "safe", or "max"
- Fix the config/env value casing and spelling (values are case-sensitive, lowercase)
- Leave PolicyMode empty ("") to get the default "safe" mode
Example fix
// before req.PolicyMode = "Strict" // after req.PolicyMode = "max" // or "record" / "safe"
Defensive patterns
Strategy: validation
Validate before calling
var validModes = map[string]bool{"": true, "record": true, "safe": true, "max": true}
if !validModes[req.PolicyMode] {
return fmt.Errorf("invalid policy mode %q", req.PolicyMode)
} Type guard
func validPolicyMode(m string) bool { return m == "" || m == "record" || m == "safe" || m == "max" } Prevention
- Define policy modes as typed constants, never raw strings from config
- Trim and lowercase policy values read from config before sending
- Leave PolicyMode unset to rely on the "safe" default
When it happens
Trigger: Calling Handle with PolicyMode set to anything other than "", "record", "safe", or "max" (e.g. "strict", "SAFE", "paranoid" from config or env).
Common situations: Config file or environment variable carrying a policy name from a different tool; case mismatches; user edits to policy settings.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- cave_breaker_retry_backoff_invalid
- cave_breaker_retry_requires_budget
- cave_breaker_retry_spend_invalid
- cave_breaker_threshold_invalid
- cave_budget_denomination_ambiguous
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/06cde5d0ed5fd519.
Report an issue: GitHub.
Appendix: source
Thrown at proxy/internal/nativeruntime/runtime.go:225
sessionLock := r.sessionLock(request.Session.ID)
sessionLock.Lock()
defer sessionLock.Unlock()
if request.ProtocolVersion != ProtocolVersion {
return Response{}, fmt.Errorf("native runtime: unsupported protocol version %d", request.ProtocolVersion)
}
if _, ok := eventTypes[request.Event.Type]; !ok {
return Response{}, fmt.Errorf("native runtime: unknown event %q", request.Event.Type)
}
if strings.TrimSpace(request.Session.ID) == "" {
return Response{}, errors.New("native runtime: session id is required")
}
policyMode := request.PolicyMode
if policyMode == "" {
policyMode = "safe"
}
if policyMode != "record" && policyMode != "safe" && policyMode != "max" {
return Response{}, fmt.Errorf("native runtime: unknown policy mode %q", policyMode)
}
request.PolicyMode = policyMode
profile, features, err := resolveProfile(request.Profile, policyMode)
if err != nil {
return Response{}, err
}
request.Profile = profile
r.mu.Lock()
r.lastActivity = time.Now()
// Listener lifetime is independent of session bookkeeping. Prune abandoned
// correlation entries lazily so a persistent proxy does not retain them
// forever when a host disappears without session.end.
for sessionID, activity := range r.activeSessions {
if r.lastActivity.Sub(activity.At) >= 30*time.Minute {
delete(r.activeSessions, sessionID)
}
}
if request.Event.Type == "session.end" {View on GitHub (pinned to 3ee70a1026)