JuliusBrussee/caveman · warning · Error
cave_harness_upstream_version_invalid
cave_harness_upstream_version_invalid
Error message
cave_harness_upstream_version_invalid
What it means
SanitizeAttributes rejects any single attribute value longer than MaxAttributeValueBytes (4096 bytes). The error names the offending key with %q, so the message pinpoints which attribute to trim. Like the other limits it fails closed so callers can reject or rewrite the record before export.
Source
Thrown at packages/agent/src/adapters.ts:93
}
export interface HarnessAdapterManifest extends HarnessAdapterIdentity {
schemaVersion: 1;
harness: HarnessID;
wireContract: Readonly<Record<string, unknown>>;
}
export function createHarnessAdapter(
id: HarnessID,
identity: HarnessAdapterIdentity,
wireContract: Readonly<Record<string, unknown>>,
invoke: HarnessInvoke,
): HarnessAdapter {
if (!/^[0-9A-Za-z][0-9A-Za-z._-]{0,63}$/.test(identity.adapterVersion)) {
throw new Error("cave_harness_adapter_version_invalid");
}
if (!/^[0-9A-Za-z][0-9A-Za-z._+-]{0,127}$/.test(identity.upstreamVersion)) {
throw new Error("cave_harness_upstream_version_invalid");
}
if (!/^[0-9a-f]{64}$/.test(identity.bundleSHA256) ||
!/^[0-9a-f]{64}$/.test(identity.dependencyLockSHA256)) {
throw new Error("cave_harness_artifact_digest_invalid");
}
const manifest = deepFreeze({
schemaVersion: 1 as const,
harness: id,
adapterVersion: identity.adapterVersion,
upstreamVersion: identity.upstreamVersion,
bundleSHA256: identity.bundleSHA256,
dependencyLockSHA256: identity.dependencyLockSHA256,
wireContract: canonicalRecord(wireContract),
});
const contractSHA256 = sha256(stableStringify(manifest));
return Object.freeze({
id,
version: identity.adapterVersion,View on GitHub (pinned to 27d5a3981a)
Solutions
- Truncate large values at the call site and keep a hash or length alongside: value[:min(len(value), 4096)] with a truncated flag.
- Move large payloads to a side channel (log, object store) and store only a reference or digest in the attribute.
- Exclude known-fat keys (body, payload, stack) from attributes entirely.
Example fix
// before
attrs["sql.query"] = query // query can exceed 4 KiB
// after
const max = telemetry.MaxAttributeValueBytes
q := query
truncated := false
if len(q) > max {
q = q[:max]
truncated = true
}
attrs["sql.query"] = q
if truncated {
attrs["sql.query.truncated"] = "true"
} Defensive patterns
Strategy: validation
Validate before calling
func clampValue(key, v string) (string, bool) {
const max = telemetry.MaxAttributeValueBytes
if len(v) <= max {
return v, true
}
return v[:max], false // truncated; caller may set a truncation flag attribute
}
for k, v := range raw {
if cv, ok := clampValue(k, v); ok {
attrs[k] = cv
} else {
attrs[k] = cv
attrs[k+".truncated"] = "true"
}
} Type guard
func validAttrValue(v string) bool {
return len(v) <= telemetry.MaxAttributeValueBytes
} Prevention
- Truncate body/query/stack-trace values before attaching them to spans.
- Store large payloads out-of-band (logs, blob store) and reference them by id or digest.
- Add tests that feed oversized values and assert the truncation path, not the error path.
When it happens
Trigger: Calling SanitizeAttributes where an allowlisted key holds a value over 4 KiB — typical offenders: full request/response bodies, stack traces, serialized JSON payloads, base64 blobs stored as attribute values.
Common situations: Recording the whole error body or SQL query as a span attribute; dumping JSON documents or base64-encoded payloads into attributes; capturing full stack traces from deeply recursive panics.
Related errors
- cave_harness_artifact_digest_invalid
- option not found
- cave_harness_adapter_version_invalid
- cave_sandbox_input_limit
- hook payload too large
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/b69a72c9f0fd4984.
Report an issue: GitHub.