JuliusBrussee/caveman · error

invalid agent evidence identity

Error message

invalid agent evidence identity

What it means

Returned by Store.AgentEvidenceForBuild when the session/build/plan identity fails validation before any query: sessionID must pass validEvidenceToken (1-256 chars, only [A-Za-z0-9._:-]) and buildSHA256/planSHA256 must each be exactly 64 lowercase hex chars. The method fails closed — partial or malformed identity yields no evidence rather than a fuzzy match.

Source

Thrown at proxy/internal/store/store.go:567

	ContextBill                  string `json:"context_bill"`
	TransformTrace               string `json:"transform_trace"`
	TransformLocation            string `json:"transform_location"`
	CacheEpoch                   string `json:"cache_epoch"`
	CachePrefixSHA256            string `json:"declared_cache_prefix_sha256"`
	ProviderCachePrefixSHA256    string `json:"provider_cache_prefix_sha256"`
	ProviderCacheComponentSHA256 string `json:"provider_cache_component_sha256"`
	CacheBoundaryKnown           bool   `json:"cache_boundary_known"`
	RecoveryHandle               string `json:"recovery_handle"`
	CompressionTokensBefore      int64  `json:"compression_tokens_before"`
	CompressionTokensAfter       int64  `json:"compression_tokens_after"`
	Basis                        string `json:"basis"`
}

// AgentEvidenceForBuild returns all requests for one exact session/build/plan
// tuple in provider-call order. Partial or malformed identity fails closed.
func (s *Store) AgentEvidenceForBuild(sessionID, buildSHA256, planSHA256 string) ([]AgentEvidence, error) {
	if !validEvidenceToken(sessionID, 256) || !validDigest(buildSHA256) || !validDigest(planSHA256) {
		return nil, fmt.Errorf("invalid agent evidence identity")
	}
	rows, err := s.db.Query(
		`SELECT ts, request_id, session_id, agent_build_sha256, efficiency_plan_sha256,
		        COALESCE(provider,''), COALESCE(model,''), COALESCE(status_code,0),
		        COALESCE(input_tokens,0), COALESCE(output_tokens,0), COALESCE(cached_input_tokens,0),
		        COALESCE(cache_creation_input_tokens,0), COALESCE(reasoning_tokens,0),
		        COALESCE(token_usage_basis,'unavailable'), COALESCE(raw_request_sha256,''),
		        COALESCE(transformed_request_sha256,''), COALESCE(request_hash_complete,0), COALESCE(optimization_ids,''),
		        COALESCE(context_bill,''), COALESCE(transform_trace,''), COALESCE(transform_location,''),
		        COALESCE(cache_epoch,''), COALESCE(cache_prefix_sha256,''),
		        COALESCE(provider_cache_prefix_sha256,''), COALESCE(provider_cache_component_sha256,''),
		        COALESCE(cache_boundary_known,0), COALESCE(recovery_handle,''),
		        COALESCE(compression_tokens_before,0), COALESCE(compression_tokens_after,0), basis
		   FROM requests
		  WHERE session_id = ? AND agent_build_sha256 = ? AND efficiency_plan_sha256 = ?
		  ORDER BY id ASC
		  LIMIT 500`,
		sessionID, buildSHA256, planSHA256,

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Pass raw 64-char lowercase hex digests: hex.EncodeToString(sum[:]) with no prefix, no trimming needed
  2. Keep session ids alphanumeric plus . _ : - only, and trim whitespace/quotes before calling
  3. Validate identity with the same rules client-side before invoking the CLI (see typeGuard)
  4. If the digest genuinely is uppercase, normalize with strings.ToLower before the call

Example fix

# before
caveman-proxy agent-evidence --session "'sess-1'" --build sha256:9f2a... --plan 3c1f
# invalid agent evidence identity

# after
caveman-proxy agent-evidence --session sess-1 --build 9f2a...64hex --plan 3c1f...64hex
Defensive patterns

Strategy: validation

Validate before calling

func validEvidenceArgs(session, build, plan string) bool {
    return validToken(session, 256) && isDigest(build) && isDigest(plan)
}
func isDigest(s string) bool {
    if len(s) != 64 { return false }
    for _, c := range s {
        if !((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')) { return false }
    }
    return true
}
func validToken(s string, max int) bool {
    if s == "" || len(s) > max { return false }
    for _, c := range s {
        if !((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || strings.ContainsRune("._:-", c)) { return false }
    }
    return true
}

Type guard

func isValidEvidenceCall(sessionID, buildSHA256, planSHA256 string) error {
    if !validToken(sessionID, 256) { return fmt.Errorf("session id malformed") }
    if !isDigest(buildSHA256) || !isDigest(planSHA256) { return fmt.Errorf("digests must be 64-char lowercase hex") }
    return nil
}

Try / catch

ev, err := st.AgentEvidenceForBuild(session, build, plan)
if err != nil && strings.Contains(err.Error(), "invalid agent evidence identity") {
    return fmt.Errorf("usage: agent-evidence --session <id> --build <64-hex> --plan <64-hex> (no sha256: prefix)")
}

Prevention

When it happens

Trigger: Calling AgentEvidenceForBuild with a SHA that is uppercase, shorter/longer than 64, or has a 'sha256:' prefix left on; a session id containing spaces, slashes, or other characters outside [A-Za-z0-9._:-]; an empty string argument.

Common situations: Passing a digest computed with hex.EncodeToString but then prefixed for display ('sha256:ab...') and not stripped; copying session ids with surrounding quotes/whitespace from logs; passing a git commit SHA (40 hex chars) where a 64-char content digest is expected; shell argument truncation mangling the value.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/642eb3889c6a36a7. Report an issue: GitHub.