{"record":{"id":"a8615455fa1ad224","repo":"thedotmack/claude-mem","slug":"hook-input-unavailable-skipping-hook-error-instanceof-error","errorCode":null,"errorMessage":"Hook input unavailable, skipping hook: ${error instanceof Error ? error.message : error}","messagePattern":"Hook input unavailable, skipping hook: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"info","filePath":"src/cli/hook-command.ts","lineNumber":141,"sourceCode":"  // 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.\n      await recordWorkerUnreachable();\n      exitGraceful(options);\n      return HOOK_EXIT_CODES.SUCCESS;\n    }\n\n    logger.error('HOOK', `Hook error: ${error instanceof Error ? error.message : error}`, {}, error instanceof Error ? error : undefined);","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d8bc9755e74915e5c3b999181e10a67c889bce2a/src/cli/hook-command.ts#L123-L159","documentation":"After AdapterRejectedInput, hookCommand also checks isNonBlockingHookInputError: errors meaning hook input was simply unavailable (no/empty stdin, unreadable stdin stream) rather than invalid. These are logged with this message, a no-op result is emitted, and the hook exits with SUCCESS — the hook never blocks the host session on missing input.","triggerScenarios":"The hook process receives no stdin payload: invoked outside a hook context, stdin closed early by the host, TTY-attached manual run with no piped input, or the platform writes nothing because the event carried no data.","commonSituations":"Running `claude-mem hook` directly in a terminal during debugging; hook registered on an event that sends no body; shell redirection mistakes in settings.json; platform bug closing stdin prematurely.","solutions":["When testing, always pipe a sample payload: cat sample.json | claude-mem hook ...","Verify the hook entry in settings.json is registered on an event that actually provides input JSON","Check that no shell wrapper (script/sudo) detaches stdin before the hook runs","Confirm Claude Code version compatibility so it actually writes the payload to the hook's stdin"],"exampleFix":"// before\nclaude-mem hook --event Stop   # no stdin -> this warning\n// after\necho '{\"session_id\":\"abc\",\"transcript_path\":\"/tmp/t.jsonl\"}' | claude-mem hook --event Stop","handlingStrategy":"fallback","validationCode":"let raw = '';\ntry { raw = readFileSync(0, 'utf8'); } catch { raw = ''; }\nif (!raw.trim()) {\n  emitModelContext(adapter, buildNoOpResult(event));\n  exitGraceful(options);\n  process.exit(HOOK_EXIT_CODES.SUCCESS);\n}","typeGuard":"function hasStdinPayload(): boolean { try { return readFileSync(0, 'utf8').trim().length > 0; } catch { return false; } }","tryCatchPattern":"try { /* pipeline */ } catch (error) {\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}","preventionTips":["Never invoke hook commands without piped stdin in scripts/tests","Check hook registration so the platform always supplies a payload","Avoid wrappers (sudo, script) that detach stdin","Emit a no-op result and exit 0 so the host session is never blocked"],"tags":["hook","stdin","missing-input","graceful-skip"],"backgroundTag":"json-parse-error","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"}