{"record":{"id":"812c0c850c59bbef","repo":"thedotmack/claude-mem","slug":"adapter-rejected-input-error-reason-skipping-hook","errorCode":null,"errorMessage":"Adapter rejected input (${error.reason}), skipping hook","messagePattern":"Adapter rejected input \\((.+?)\\), skipping hook","errorType":"console","errorClass":"AdapterRejectedInput","httpStatus":null,"severity":"warning","filePath":"src/cli/hook-command.ts","lineNumber":135,"sourceCode":"  // We BUFFER stderr during handler execution so that unsolicited writes from\n  // third-party libraries don't leak into model context. The buffer is FLUSHED\n  // only when we choose to surface (logger errors at the catch-all branch,\n  // fail-loud counter from worker-utils, blocking-error path). Successful exits\n  // drop the buffer — preserving the original \"quiet on success\" behavior.\n  //\n  // To bypass the buffer for a specific write, use emitDiagnostic /\n  // emitBlockingError from src/shared/hook-io.ts. Direct process.stderr.write\n  // calls are buffered.\n  const stderrBuffer = installHookStderrBuffer();\n\n  const adapter = getPlatformAdapter(platform);\n  const handler = getEventHandler(event);\n\n  try {\n    return await executeHookPipeline(adapter, handler, platform, options);\n  } catch (error) {\n    if (error instanceof AdapterRejectedInput) {\n      logger.warn('HOOK', `Adapter rejected input (${error.reason}), skipping hook`);\n      emitModelContext(adapter, buildNoOpResult(event));\n      exitGraceful(options);\n      return HOOK_EXIT_CODES.SUCCESS;\n    }\n    if (isNonBlockingHookInputError(error)) {\n      logger.warn('HOOK', `Hook input unavailable, skipping hook: ${error instanceof Error ? error.message : error}`);\n      emitModelContext(adapter, buildNoOpResult(event));\n      exitGraceful(options);\n      return HOOK_EXIT_CODES.SUCCESS;\n    }\n    if (isWorkerUnavailableError(error)) {\n      logger.warn('HOOK', `Worker unavailable, skipping hook: ${error instanceof Error ? error.message : error}`);\n      // EXIT_SIGNAL per CLAUDE.md: transient worker errors exit 0 to avoid\n      // Windows Terminal tab accumulation. The fail-loud counter (worker-utils\n      // recordWorkerUnreachable) handles the surface-after-N-failures path and\n      // emits the threshold-gated hook_failed telemetry internally. Awaited:\n      // when the count JUST reaches the threshold it sends the event and then\n      // exits 2; exitGraceful below would kill a pending POST mid-flight.","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d8bc9755e74915e5c3b999181e10a67c889bce2a/src/cli/hook-command.ts#L117-L153","documentation":"hookCommand builds a platform adapter and runs the hook pipeline. If the adapter throws AdapterRejectedInput — meaning the hook's stdin payload did not conform to the expected schema for that event/platform — the warning is logged with error.reason, a no-op result is emitted so the model context stays clean, and the process exits gracefully with SUCCESS. The hook is intentionally non-blocking on bad input.","triggerScenarios":"Claude Code (or another platform) pipes a payload the adapter cannot accept: empty stdin, JSON missing required fields for the event type, wrong event shape for the configured handler, or a payload from an unsupported platform version.","commonSituations":"Hook misconfigured in settings.json (wrong event wired to this command); running the hook command manually with no stdin; Claude Code version change altering the hook payload schema; another plugin emitting malformed input.","solutions":["Echo the hook payload to a file and validate it against the expected event schema to see which field error.reason flags","Check .claude/settings.json hook wiring — ensure the correct event (Stop/SessionEnd/etc.) invokes this command","Update claude-mem and Claude Code together so payload schemas match","Test the hook manually with a known-good sample payload via cat payload.json | claude-mem hook"],"exampleFix":"// before\ncat payload.json | claude-mem hook --event UnknownEvent\n// after\ncat payload.json | claude-mem hook --event Stop","handlingStrategy":"validation","validationCode":"const raw = readFileSync(0, 'utf8');\nconst payload = JSON.parse(raw); // validate before invoking hookCommand\nif (!payload || typeof payload.session_id !== 'string' || !payload.hook_event_name) {\n  throw new AdapterRejectedInput('missing required hook fields');\n}","typeGuard":"function isHookPayload(v: unknown): v is { session_id: string; hook_event_name: string } {\n  return typeof v === 'object' && v !== null && 'session_id' in v && 'hook_event_name' in v;\n}","tryCatchPattern":"try {\n  return await executeHookPipeline(adapter, handler, platform, options);\n} catch (error) {\n  if (error instanceof AdapterRejectedInput) {\n    logger.warn('HOOK', `Adapter rejected input (${error.reason}), skipping hook`);\n    emitModelContext(adapter, buildNoOpResult(event));\n    exitGraceful(options);\n    return HOOK_EXIT_CODES.SUCCESS;\n  }\n}","preventionTips":["Register hooks only on supported events in settings.json","Test the hook with a recorded valid payload before deploying","Keep claude-mem and Claude Code versions aligned","Always pipe stdin when invoking the hook manually"],"tags":["hook","validation","adapter","graceful-skip"],"backgroundTag":"invalid-json-response","analyzedSha":"d8bc9755e74915e5c3b999181e10a67c889bce2a","analyzedAt":"2026-09-17T16:40:26.182Z","contentChangedAt":"2026-09-17T16:40:26.182Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}