{"record":{"id":"b69a72c9f0fd4984","repo":"JuliusBrussee/caveman","slug":"cave-harness-upstream-version-invalid","errorCode":"cave_harness_upstream_version_invalid","errorMessage":"cave_harness_upstream_version_invalid","messagePattern":"cave_harness_upstream_version_invalid","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"packages/agent/src/adapters.ts","lineNumber":93,"sourceCode":"}\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));\n  return Object.freeze({\n    id,\n    version: identity.adapterVersion,","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/agent/src/adapters.ts#L75-L111","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nattrs[\"sql.query\"] = query // query can exceed 4 KiB\n\n// after\nconst max = telemetry.MaxAttributeValueBytes\nq := query\ntruncated := false\nif len(q) > max {\n    q = q[:max]\n    truncated = true\n}\nattrs[\"sql.query\"] = q\nif truncated {\n    attrs[\"sql.query.truncated\"] = \"true\"\n}","handlingStrategy":"validation","validationCode":"func clampValue(key, v string) (string, bool) {\n    const max = telemetry.MaxAttributeValueBytes\n    if len(v) <= max {\n        return v, true\n    }\n    return v[:max], false // truncated; caller may set a truncation flag attribute\n}\n\nfor k, v := range raw {\n    if cv, ok := clampValue(k, v); ok {\n        attrs[k] = cv\n    } else {\n        attrs[k] = cv\n        attrs[k+\".truncated\"] = \"true\"\n    }\n}","typeGuard":"func validAttrValue(v string) bool {\n    return len(v) <= telemetry.MaxAttributeValueBytes\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["telemetry","limits","payload-size"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}