{"record":{"id":"342fa956f11c86d0","repo":"JuliusBrussee/caveman","slug":"hook-payload-too-large","errorCode":null,"errorMessage":"hook payload too large","messagePattern":"hook payload too large","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/native-hook-fast.ts","lineNumber":140,"sourceCode":"function profile(): NativeProfile {\n  const explicit = process.env.CAVEMAN_NATIVE_PROFILE?.trim().toLowerCase() as NativeProfile | undefined;\n  if (explicit) return PROFILES.has(explicit) ? explicit : \"record-only\";\n  const mode = policyMode();\n  return mode === \"record\" ? \"record-only\" : mode === \"max\" ? \"full-max\" : \"full-safe\";\n}\n\n// Return as soon as the accumulated bytes parse as one complete JSON payload\n// instead of waiting for EOF. The host writes one object and closes, but under\n// the Windows pipe implementation that close can lag arbitrarily (#729/#833),\n// and a hook that blocks on EOF spends the host's whole budget waiting for a\n// close it already has all the data for.\nasync function stdin(): Promise<Buffer> {\n  const chunks: Buffer[] = [];\n  let bytes = 0;\n  for await (const chunk of process.stdin) {\n    const value = Buffer.from(chunk);\n    bytes += value.length;\n    if (bytes > 2 * 1024 * 1024) throw new Error(\"hook payload too large\");\n    chunks.push(value);\n    const joined = Buffer.concat(chunks);\n    // A partial payload throws and we wait for more bytes.\n    try { JSON.parse(joined.toString(\"utf8\")); } catch { continue; }\n    return joined;\n  }\n  return Buffer.concat(chunks);\n}\n\nfunction bounded(value: unknown, max = 160): string | undefined {\n  if (typeof value !== \"string\") return undefined;\n  const clean = value.replace(/[\\r\\n\\0]/g, \" \").trim();\n  return clean ? clean.slice(0, max) : undefined;\n}\n\nfunction digestObject(value: unknown): { bytes: number; sha256: string } | undefined {\n  if (value && typeof value === \"object\" && !Array.isArray(value)) {\n    const candidate = value as Record<string, unknown>;","sourceCodeStart":122,"sourceCodeEnd":158,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/cli/src/native-hook-fast.ts#L122-L158","documentation":"Thrown by stdin() in the native hook fast path when the JSON payload piped into the hook process exceeds 2 MiB. The hook reads stdin incrementally and aborts as soon as the accumulated byte count crosses the limit, protecting the native binary from unbounded memory use. Callers (Claude/agent hook pipelines) sending oversized transcripts or attachments trigger it.","triggerScenarios":"Piping a hook payload >2*1024*1024 bytes into the native hook binary's stdin, e.g. a conversation transcript with very large embedded file contents or base64 attachments.","commonSituations":"Agent configured to feed full session transcripts to hooks, large pasted documents/images included in the payload, or a misconfigured hook forwarding an entire log file instead of an event summary.","solutions":["Reduce the hook payload: send only the event fields the hook needs, not the full transcript.","Truncate or strip large message contents/attachments before invoking the hook.","Increase or bypass the limit by pre-filtering in a wrapper script that pipes a slimmed payload.","Move big data to a file and pass a path in the JSON payload instead of inline content."],"exampleFix":"// before\n{ \"transcript\": <entire 5MB session json> } | caveman-hook\n// after\n{ \"type\": \"PostToolUse\", \"tool\": \"Bash\", \"summary\": \"...\" } | caveman-hook","handlingStrategy":"validation","validationCode":"const payload = JSON.stringify(hookEvent);\nif (Buffer.byteLength(payload) > 2 * 1024 * 1024) {\n  // strip or truncate large fields before piping to the hook\n  delete hookEvent.transcript;\n}\nprocess.stdout.write(JSON.stringify(hookEvent));","typeGuard":null,"tryCatchPattern":"try {\n  runHookWithStdin(payload);\n} catch (e) {\n  if (e instanceof Error && e.message === \"hook payload too large\") {\n    console.error(\"Hook payload exceeds 2 MiB; trim transcript/attachments and resend\");\n  } else throw e;\n}","preventionTips":["Send minimal event JSON to hooks, not full transcripts","Store large content in files and reference paths in the payload","Cap message content lengths before invoking hooks","Keep the 2 MiB limit in mind when designing hook integrations"],"tags":["payload","limit","stdin","hook"],"backgroundTag":"payload-too-large","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}