JuliusBrussee/caveman · error
native runtime: invalid decision id
Error message
native runtime: invalid decision id
What it means
ExplainDecision validates the decision id against the strict pattern ^dec_[0-9a-f]{24}$ before touching the store. Ids not matching (wrong prefix, wrong length, uppercase, or non-hex characters) are rejected as invalid rather than looked up — malformed ids never become store queries.
Source
Thrown at proxy/internal/nativeruntime/explain.go:35
// Ledger record. It contains decision basis, never raw prompt or tool output.
type DecisionExplanation struct {
Schema string `json:"schema"`
DecisionID string `json:"decision_id"`
SessionID string `json:"session_id"`
TimestampMS int64 `json:"timestamp_ms"`
Action string `json:"action"`
Reason string `json:"reason"`
InputBasis map[string]any `json:"input_basis"`
AlternativesRejected []string `json:"alternatives_rejected"`
TaskStateBefore string `json:"task_state_before"`
TaskStateAfter string `json:"task_state_after"`
Currentness string `json:"currentness"`
RecoveryRef string `json:"recovery_ref,omitempty"`
}
func ExplainDecision(store *ccr.Store, decisionID string) (DecisionExplanation, error) {
if !decisionIDPattern.MatchString(decisionID) {
return DecisionExplanation{}, errors.New("native runtime: invalid decision id")
}
object, err := store.FindTaskDecision(decisionID)
if err != nil {
return DecisionExplanation{}, err
}
var record struct {
Schema string `json:"schema"`
DecisionID string `json:"decision_id"`
TimestampMS int64 `json:"timestamp_ms"`
Action string `json:"action"`
Reason string `json:"reason"`
InputBasis map[string]any `json:"input_basis"`
AlternativesRejected []string `json:"alternatives_rejected"`
TaskStateBefore string `json:"task_state_before"`
TaskStateAfter string `json:"task_state_after"`
Currentness string `json:"currentness"`
RecoveryRef string `json:"recovery_ref"`
}View on GitHub (pinned to 27d5a3981a)
Solutions
- Use the exact dec_-prefixed 24-lowercase-hex id returned when the decision was recorded
- Validate client-side with regexp `^dec_[0-9a-f]{24}$` before calling
- If ids come through case-insensitive channels, lowercase them first
Example fix
// before
exp, err := nativeruntime.ExplainDecision(store, decisionID) // e.g. "DEC_AABB..." or ""
// after
var decIDRe = regexp.MustCompile(`^dec_[0-9a-f]{24}$`)
if !decIDRe.MatchString(decisionID) {
return fmt.Errorf("malformed decision id")
}
exp, err := nativeruntime.ExplainDecision(store, decisionID) Defensive patterns
Strategy: validation
Validate before calling
var decisionIDRe = regexp.MustCompile(`^dec_[0-9a-f]{24}$`)
if !decisionIDRe.MatchString(decisionID) {
return errors.New("malformed decision id")
}
exp, err := nativeruntime.ExplainDecision(store, decisionID) Type guard
func isDecisionID(s string) bool {
re := regexp.MustCompile(`^dec_[0-9a-f]{24}$`)
return re.MatchString(s)
} Prevention
- Pass decision ids through verbatim from the runtime that issued them
- Lowercase ids from case-insensitive channels before validating
When it happens
Trigger: Calling ExplainDecision with a decision id that is empty, has a typo, uses uppercase hex, is a full 64-hex sha256 instead of the 24-hex dec_ id, or was re-encoded (base64, quoted) in transit.
Common situations: Copying a different object's id (ccr_obj_...) instead of the decision id; case-folding middleware uppercasing ids; truncation of the id in logs or terminal copy-paste.
Related errors
- native runtime: session id is required
- cachebench: nil corpus reader
- message exceeds byte limit
- tool message requires tool_call_id
- cachebench: invalid corpus
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/53a888deb5e0cc24.
Report an issue: GitHub.