JuliusBrussee/caveman · error

ccr: typed object session_id is required

Error message

ccr: typed object session_id is required

What it means

Validation error from prepareObject in the CCR typed-object path: every typed Object must carry a non-blank SessionID, and unknown/blank values fail closed. PutObject refuses to store the object without it because session scoping is part of the object's identity and retrieval semantics.

Solutions

  1. Set obj.SessionID to the active session's ID before calling PutObject.
  2. Add a constructor/helper that requires sessionID so it cannot be omitted.
  3. If unmarshaling from JSON, validate session_id is present and non-empty before PutObject.
  4. Trim and check strings.TrimSpace(sessionID) != "" at the call site.

Example fix

// before
obj := ccr.Object{Type: ccr.TypeToolResult, Data: data}
handle, err := store.PutObject(obj)

// after
obj := ccr.Object{Type: ccr.TypeToolResult, Data: data, SessionID: session.ID}
if strings.TrimSpace(obj.SessionID) == "" { return errors.New("missing session id") }
handle, err := store.PutObject(obj)
Defensive patterns

Strategy: validation

Validate before calling

func validObject(o ccr.Object) bool {
    return strings.TrimSpace(o.SessionID) != ""
}

Try / catch

if err := ensureSessionID(&obj, session.ID); err != nil { return err }
if _, err := store.PutObject(obj); err != nil {
    if strings.Contains(err.Error(), "session_id is required") {
        return fmt.Errorf("object rejected: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling PutObject/putObject with Object{...} where SessionID is "" or whitespace-only; constructing objects programmatically and forgetting to propagate the session context.

Common situations: Background/worker code creating objects without the request's session ID; refactoring that dropped a field from the struct literal; deserializing objects from JSON where session_id was omitted.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/494eddd442d699e5. Report an issue: GitHub.

Appendix: source

Thrown at engine/ccr/store.go:110

	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 3ee70a1026)