{"record":{"id":"0f3187157d91a122","repo":"JuliusBrussee/caveman","slug":"cave-harness-signal-invalid","errorCode":"cave_harness_signal_invalid","errorMessage":"cave_harness_signal_invalid","messagePattern":"cave_harness_signal_invalid","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/agent/src/adapters.ts","lineNumber":626,"sourceCode":"function 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\nfunction snapshotRequest(request: HarnessRequest): Readonly<HarnessRequest> {\n  try {\n    const { signal, ...serializable } = request;\n    const snapshot = deepFreeze(structuredClone(serializable));\n    if (signal === undefined) return snapshot;\n    if (typeof signal.aborted !== \"boolean\" || typeof signal.addEventListener !== \"function\") {\n      throw new Error(\"cave_harness_signal_invalid\");\n    }\n    return Object.freeze({ ...snapshot, signal });\n  } catch {\n    throw new Error(\"cave_harness_request_invalid\");\n  }\n}\n\nfunction snapshotExecution(value: HarnessExecution): Readonly<HarnessExecution> {\n  if (!isRecord(value) ||\n      !Array.isArray(value.evaluatedTransformIDs) ||\n      !Array.isArray(value.appliedTransformIDs)) {\n    throw new Error(\"cave_harness_incomplete_evidence\");\n  }\n  return deepFreeze({\n    terminal: value.terminal,\n    text: value.text,\n    provider: value.provider,\n    model: value.model,","sourceCodeStart":608,"sourceCodeEnd":644,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/agent/src/adapters.ts#L608-L644","documentation":"`snapshotRequest` validates an optional `AbortSignal`: if `request.signal` is defined, it must expose `aborted: boolean` and `addEventListener: function`. Anything else (a plain object masquerading as a signal, a stubbed signal) throws `cave_harness_signal_invalid`. Note: in the current source this throw happens inside the function's `try` block, so the enclosing `catch` rewrites it into `cave_harness_request_invalid` — callers will in practice observe the request_invalid code; the signal_invalid condition is still the underlying cause to fix.","triggerScenarios":"Setting `request.signal` to a mock object like `{ aborted: false }` without `addEventListener`; a custom abort implementation missing the DOM-standard methods; a signal polyfill that only partially implements the interface.","commonSituations":"Test doubles replacing `AbortController` with minimal fakes; older runtimes without full `AbortSignal`; passing a `EventTarget`-like cancellation token from a different library instead of a standard `AbortSignal`.","solutions":["Pass a real `AbortSignal` from `new AbortController().signal`, or omit `signal` entirely if cancellation is not needed.","In tests, use Node's built-in `AbortController` rather than hand-rolled signal stubs.","If you have a custom cancellation source, bridge it: create an `AbortController`, forward your events, and pass its signal."],"exampleFix":"// before\nawait adapter.run({ ..., signal: { aborted: false } as AbortSignal });\n\n// after\nconst controller = new AbortController();\nawait adapter.run({ ..., signal: controller.signal });","handlingStrategy":"type-guard","validationCode":"function isAbortSignalLike(v: unknown): v is AbortSignal {\n  return v === undefined || (\n    typeof v === \"object\" && v !== null &&\n    typeof (v as AbortSignal).aborted === \"boolean\" &&\n    typeof (v as AbortSignal).addEventListener === \"function\"\n  );\n}\nif (!isAbortSignalLike(request.signal)) throw new Error(\"pass a real AbortSignal or omit it\");","typeGuard":"function isAbortSignalLike(v: unknown): v is AbortSignal {\n  return typeof v === \"object\" && v !== null &&\n    typeof (v as AbortSignal).aborted === \"boolean\" &&\n    typeof (v as AbortSignal).addEventListener === \"function\";\n}","tryCatchPattern":"try {\n  await adapter.run(request);\n} catch (err) {\n  // note: current source rewrites this to cave_harness_request_invalid (error 29);\n  // treat that code with a signal present as this condition\n  if (err instanceof Error && err.message === \"cave_harness_request_invalid\" && request.signal) {\n    // replace the fake signal with new AbortController().signal and retry\n  }\n}","preventionTips":["Always use the platform AbortController; never hand-roll signal objects.","Omit signal when cancellation is not needed rather than passing a placeholder.","Bridge custom cancellation sources through a real AbortController."],"tags":["adapter","abort-signal","validation","testing"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}