{"record":{"id":"46e50833e658b55f","repo":"JuliusBrussee/caveman","slug":"cave-harness-adapter-version-invalid","errorCode":"cave_harness_adapter_version_invalid","errorMessage":"cave_harness_adapter_version_invalid","messagePattern":"cave_harness_adapter_version_invalid","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"packages/agent/src/adapters.ts","lineNumber":90,"sourceCode":"  upstreamVersion: string;\n  bundleSHA256: string;\n  dependencyLockSHA256: string;\n}\n\nexport interface HarnessAdapterManifest extends HarnessAdapterIdentity {\n  schemaVersion: 1;\n  harness: HarnessID;\n  wireContract: Readonly<Record<string, unknown>>;\n}\n\nexport function createHarnessAdapter(\n  id: HarnessID,\n  identity: HarnessAdapterIdentity,\n  wireContract: Readonly<Record<string, unknown>>,\n  invoke: HarnessInvoke,\n): HarnessAdapter {\n  if (!/^[0-9A-Za-z][0-9A-Za-z._-]{0,63}$/.test(identity.adapterVersion)) {\n    throw new Error(\"cave_harness_adapter_version_invalid\");\n  }\n  if (!/^[0-9A-Za-z][0-9A-Za-z._+-]{0,127}$/.test(identity.upstreamVersion)) {\n    throw new Error(\"cave_harness_upstream_version_invalid\");\n  }\n  if (!/^[0-9a-f]{64}$/.test(identity.bundleSHA256) ||\n      !/^[0-9a-f]{64}$/.test(identity.dependencyLockSHA256)) {\n    throw new Error(\"cave_harness_artifact_digest_invalid\");\n  }\n  const manifest = deepFreeze({\n    schemaVersion: 1 as const,\n    harness: id,\n    adapterVersion: identity.adapterVersion,\n    upstreamVersion: identity.upstreamVersion,\n    bundleSHA256: identity.bundleSHA256,\n    dependencyLockSHA256: identity.dependencyLockSHA256,\n    wireContract: canonicalRecord(wireContract),\n  });\n  const contractSHA256 = sha256(stableStringify(manifest));","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/agent/src/adapters.ts#L72-L108","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\nkey := \"request.header.\" + strings.ToLower(rawHeaderName) // rawHeaderName unbounded\nattrs[key] = \"present\"\n\n// after\nname := strings.ToLower(rawHeaderName)\nif len(name) > telemetry.MaxAttributeKeyBytes {\n    name = \"long-header-\" + fmt.Sprintf(\"%x\", sha256.Sum256([]byte(name)))\n}\nattrs[\"request.header.\"+name] = \"present\"","handlingStrategy":"validation","validationCode":"func sanitizeKey(k string) (string, bool) {\n    if len(k) > telemetry.MaxAttributeKeyBytes {\n        return \"\", false\n    }\n    return k, true\n}\n\nfor k, v := range raw {\n    if k2, ok := sanitizeKey(k); ok {\n        attrs[k2] = v\n    }\n}","typeGuard":"func validAttrKey(k string) bool {\n    return len(k) <= telemetry.MaxAttributeKeyBytes\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["telemetry","limits","validation"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}