JuliusBrussee/caveman · warning · Error
cave_harness_adapter_version_invalid
cave_harness_adapter_version_invalid
Error message
cave_harness_adapter_version_invalid
What it means
SanitizeAttributes rejects any single attribute key longer than MaxAttributeKeyBytes (256 bytes). Long keys bloat span payloads and are frequently malformed or injection-like, so the sanitizer fails closed instead of hashing or truncating them. The limit is checked on the sorted allowlisted keys before values are copied.
Source
Thrown at packages/agent/src/adapters.ts:90
upstreamVersion: string;
bundleSHA256: string;
dependencyLockSHA256: string;
}
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));View on GitHub (pinned to 27d5a3981a)
Solutions
- Bound the variable part of the key: hash or truncate any identifier embedded in the key and move the full value into the attribute value.
- Validate key length at the call site before adding the attribute (len(key) <= 256).
- Move unbounded labels from the key into the value or a dedicated log field.
Example fix
// before
key := "request.header." + strings.ToLower(rawHeaderName) // rawHeaderName unbounded
attrs[key] = "present"
// after
name := strings.ToLower(rawHeaderName)
if len(name) > telemetry.MaxAttributeKeyBytes {
name = "long-header-" + fmt.Sprintf("%x", sha256.Sum256([]byte(name)))
}
attrs["request.header."+name] = "present" Defensive patterns
Strategy: validation
Validate before calling
func sanitizeKey(k string) (string, bool) {
if len(k) > telemetry.MaxAttributeKeyBytes {
return "", false
}
return k, true
}
for k, v := range raw {
if k2, ok := sanitizeKey(k); ok {
attrs[k2] = v
}
} Type guard
func validAttrKey(k string) bool {
return len(k) <= telemetry.MaxAttributeKeyBytes
} Prevention
- Never compose attribute keys from unbounded input; hash or truncate identifiers used in keys.
- Validate keys at the point of attribute construction, not at export time.
- Keep keys static constants where possible; put variable data in values.
When it happens
Trigger: Calling SanitizeAttributes with at least one allowlisted key whose string length exceeds 256 bytes (e.g. a generated key like "feature.flag." + 300-char identifier, or a templated key built from a URL path).
Common situations: Composing attribute keys from unbounded user input (paths, ids, serialized labels); copying OpenTelemetry semantic-convention keys with long prefixes; key templates that append tenant or shard identifiers.
Related errors
- option not found
- cave_harness_upstream_version_invalid
- cave_harness_artifact_digest_invalid
- caveman agent: subagent maxInputChars must be a positive int
- cave_${field}_invalid
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/46e50833e658b55f.
Report an issue: GitHub.