JuliusBrussee/caveman · error
ccr: typed object session_id is required
Error message
ccr: typed object session_id is required
What it means
prepareObject (reached via PutObject) rejects any typed object whose SessionID is blank after trimming. Session identity is mandatory because every CCR object is scoped to a session for retrieval and permission checks. The error fires before any hashing or storage happens.
Source
Thrown at engine/ccr/store.go:106
OriginalByteLength int `json:"original_byte_length"`
StoredByteLength int `json:"stored_byte_length"`
Data []byte `json:"data"`
}
var objectTypes = map[ObjectType]struct{}{
ObjectFileObservation: {}, ObjectSearchResult: {}, ObjectCommandResult: {},
ObjectTestResult: {}, ObjectBuildResult: {}, ObjectDiffSnapshot: {},
ObjectTaskContract: {}, ObjectTaskDecision: {}, ObjectExecutionState: {},
ObjectDocumentationExcerpt: {}, ObjectBrowserSnapshot: {},
ObjectRepositoryMap: {}, ObjectEvidenceBundle: {},
}
func prepareObject(obj Object) (Object, error) {
if _, ok := objectTypes[obj.Type]; !ok {
return Object{}, fmt.Errorf("ccr: unknown object type %q", obj.Type)
}
if strings.TrimSpace(obj.SessionID) == "" {
return Object{}, errors.New("ccr: typed object session_id is required")
}
if obj.Currentness == "" {
obj.Currentness = Current
}
if obj.Currentness != Current && obj.Currentness != Stale && obj.Currentness != Archived {
return Object{}, fmt.Errorf("ccr: unknown currentness %q", obj.Currentness)
}
if obj.Lifecycle == "" {
obj.Lifecycle = Hot
}
if obj.Lifecycle != Hot && obj.Lifecycle != Warm && obj.Lifecycle != Cold && obj.Lifecycle != LifecycleArchived {
return Object{}, fmt.Errorf("ccr: unknown lifecycle %q", obj.Lifecycle)
}
if obj.CreatedAt.IsZero() {
obj.CreatedAt = time.Now().UTC()
} else {
obj.CreatedAt = obj.CreatedAt.UTC()
}View on GitHub (pinned to 27d5a3981a)
Solutions
- Set obj.SessionID to the active session identifier before PutObject
- If the object arrives from JSON, verify the producer emits `session_id` exactly and the struct tags match
- Fail fast at object construction: validate SessionID in your builder/helper so the store never sees it blank
Example fix
// before
obj := ccr.Object{Type: ccr.ObjectCommandResult, Data: data}
id, err := store.PutObject(obj)
// after
obj := ccr.Object{
Type: ccr.ObjectCommandResult,
SessionID: sessionID, // required
Data: data,
}
id, err := store.PutObject(obj) Defensive patterns
Strategy: validation
Validate before calling
if strings.TrimSpace(obj.SessionID) == "" {
return errors.New("session_id required before PutObject")
}
id, err := store.PutObject(obj) Type guard
func validSessionID(s string) bool { return strings.TrimSpace(s) != "" } Prevention
- Construct objects through one builder that always stamps the session id
- Match JSON tags exactly (session_id) on producers and consumers
- Validate at your API boundary, not only at the store
When it happens
Trigger: Calling PutObject(Object{...}) with SessionID omitted or set to whitespace; building objects from deserialized JSON where the session_id field was missing or misnamed (e.g. sessionId vs session_id); test fixtures that only set Type and Data.
Common situations: JSON field-name mismatch between a producer using camelCase and the Go struct's `json:"session_id"` tag; refactoring code that previously derived sessionID implicitly; copy-pasted test objects missing the field.
Related errors
- ccr: typed object byte lengths cannot be negative
- native runtime: session id is required
- cachebench: nil corpus reader
- message exceeds byte limit
- tool message requires tool_call_id
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/494eddd442d699e5.
Report an issue: GitHub.