{"record":{"id":"b5b55159040d475e","repo":"JuliusBrussee/caveman","slug":"cave-harness-wire-contract-invalid","errorCode":"cave_harness_wire_contract_invalid","errorMessage":"cave_harness_wire_contract_invalid","messagePattern":"cave_harness_wire_contract_invalid","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/agent/src/adapters.ts","lineNumber":601,"sourceCode":"  // longer authorize execution.\n  const installed = installedPackageVersion(pkg);\n  if (installed === undefined) {\n    throw new Error(`cave_${harness}_upstream_version_unresolvable`);\n  }\n  if (installed !== expected) {\n    throw new Error(`cave_${harness}_upstream_version_unsupported`);\n  }\n  if (identity.upstreamVersion !== installed) {\n    throw new Error(`cave_${harness}_upstream_version_mismatch`);\n  }\n}\n\nfunction canonicalRecord(value: Readonly<Record<string, unknown>>): Readonly<Record<string, unknown>> {\n  let encoded: string;\n  try {\n    encoded = stableStringify(value);\n  } catch {\n    throw new Error(\"cave_harness_wire_contract_invalid\");\n  }\n  const decoded = JSON.parse(encoded) as unknown;\n  if (!isRecord(decoded)) throw new Error(\"cave_harness_wire_contract_invalid\");\n  return decoded;\n}\n\nfunction deepFreeze<T>(value: T): T {\n  if (value !== null && typeof value === \"object\") {\n    Object.freeze(value);\n    for (const child of Object.values(value)) deepFreeze(child);\n  }\n  return value;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n  return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n","sourceCodeStart":583,"sourceCodeEnd":619,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/agent/src/adapters.ts#L583-L619","documentation":"`canonicalRecord` round-trips a wire payload through `stableStringify` to produce a canonical form for hashing and freezing. If `stableStringify` throws — classically because the value contains a circular reference or a value JSON cannot represent (function, symbol, BigInt, undefined inside arrays) — the adapter throws `cave_harness_wire_contract_invalid`: the payload does not satisfy the serializable wire contract the harness evidence chain requires. The payload must be plain JSON data.","triggerScenarios":"Passing a harness request/record containing a circular object graph; embedding a function, class instance, symbol, or BigInt in what should be a JSON-serializable record; a computed property getter that throws during stringification.","commonSituations":"Attaching live objects (loggers, clients, DOM nodes) into request metadata; reusing domain entities with parent pointers as wire records; a refactor that moved a closure into a previously-plain config object.","solutions":["Strip non-serializable values from the record before passing it: keep only strings, numbers, booleans, null, arrays, and plain objects.","Break circular references (delete parent/back-pointers) or map entities to plain DTOs.","If you must carry a live object, keep it outside the record — like the adapter itself does with `AbortSignal` in `snapshotRequest`."],"exampleFix":"// before\nconst payload = { prompt: \"hi\", client: someLiveClient }; // not serializable\n\n// after\nconst { client, ...payload } = config; // client stays outside the wire record\nconst wirePayload = payload; // plain JSON data only","handlingStrategy":"validation","validationCode":"function isJsonSerializable(value: unknown, seen = new Set()): boolean {\n  if (value === null || [\"string\", \"number\", \"boolean\"].includes(typeof value)) return true;\n  if (typeof value === \"object\") {\n    if (seen.has(value)) return false; // circular\n    seen.add(value);\n    return Object.values(value).every((v) => isJsonSerializable(v, seen));\n  }\n  return false; // function, symbol, bigint, undefined\n}\nif (!isJsonSerializable(record)) throw new Error(\"strip non-serializable values first\");","typeGuard":null,"tryCatchPattern":"try {\n  await adapter.run(request);\n} catch (err) {\n  if (err instanceof Error && err.message === \"cave_harness_wire_contract_invalid\") {\n    // log which record failed, strip live objects, retry with plain data\n  }\n}","preventionTips":["Keep wire records to plain JSON data; pass live objects through side channels.","JSON.round-trip payloads in dev builds to catch circular references early.","Define DTO types for anything crossing the adapter boundary."],"tags":["adapter","serialization","wire-contract","validation"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}