{"record":{"id":"8b5eb9d6330e3d78","repo":"thedotmack/claude-mem","slug":"operationtype-no-user-prompts-row-for-prompt","errorCode":null,"errorMessage":"${operationType}: no user_prompts row for prompt #${promptNumber} — ingesting anyway (session-init likely raced worker boot; see #2794/#2795)","messagePattern":"(.+?): no user_prompts row for prompt #(.+?) — ingesting anyway \\(session-init likely raced worker boot; see #2794/#2795\\)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/services/worker/validation/PrivacyCheckValidator.ts","lineNumber":32,"sourceCode":"   *    never persisted the prompt for this session (e.g. the UserPromptSubmit\n   *    hook raced worker boot, #2795). This is NOT a privacy signal — treating\n   *    it as \"private\" silently freezes EVERY observation for the session.\n   *    Allow ingestion and emit a visible warn.\n   *  - The row is PRESENT but empty after privacy stripping (''/whitespace):\n   *    the user genuinely redacted the turn → suppress.\n   */\n  static checkUserPromptPrivacy(\n    store: SessionStore,\n    contentSessionId: string,\n    promptNumber: number,\n    operationType: 'observation' | 'summarize',\n    sessionDbId: number,\n    additionalContext?: Record<string, any>\n  ): PromptPrivacyDecision {\n    const userPrompt = store.getUserPrompt(contentSessionId, promptNumber, sessionDbId);\n\n    if (userPrompt === null) {\n      logger.warn(\n        'HOOK',\n        `${operationType}: no user_prompts row for prompt #${promptNumber} — ingesting anyway (session-init likely raced worker boot; see #2794/#2795)`,\n        { sessionId: sessionDbId, contentSessionId, promptNumber, ...additionalContext }\n      );\n      return { allow: true, prompt: '' };\n    }\n\n    if (userPrompt.trim() === '') {\n      logger.debug('HOOK', `Skipping ${operationType} - user prompt was entirely private`, {\n        sessionId: sessionDbId,\n        promptNumber,\n        ...additionalContext,\n      });\n      return { allow: false, reason: 'private' };\n    }\n\n    return { allow: true, prompt: userPrompt };\n  }","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/e2d1df569a8f04075d40e92461128ece7cf04c82/src/services/worker/validation/PrivacyCheckValidator.ts#L14-L50","documentation":"PrivacyCheckValidator.checkUserPromptPrivacy looks up the user_prompts row for (contentSessionId, promptNumber, sessionDbId). When store.getUserPrompt returns null it logs this warning and returns {allow: true, prompt: ''} — privacy filtering is bypassed and observation/summarize ingestion proceeds with an empty prompt. This is a known cold-boot race (issues #2794/#2795): the session-init hook had not yet written the row when the worker processed the prompt.","triggerScenarios":"An observation or summarize operation calls checkUserPromptPrivacy before the SessionStart/session-init hook has inserted the user_prompts row — typically when the context hook races worker startup on a cold boot (~7s Chroma bind).","commonSituations":"First prompt immediately after machine reboot; worker restarting mid-session after an upgrade; heavy system load delaying the session-init hook past the observation hook.","solutions":["No data-loss action needed — ingestion proceeds and the row usually lands moments later; subsequent prompts find their rows.","If it recurs outside cold boot, check worker logs for session-init hook failures (that hook is the row writer).","Upgrade claude-mem: the ~15s cold-boot wait was added specifically to shrink this window (#2795).","Confirm the session-init hook is registered and executing in Claude Code hook config."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const row = store.getUserPrompt(contentSessionId, promptNumber, sessionDbId);\nif (row === null) {\n  // session-init hook has not landed yet — defer instead of ingesting blind\n  return { defer: true };\n}","typeGuard":"const hasUserPromptRow = (\n  store: SessionStore, csid: string, n: number, dbId: number\n): boolean => store.getUserPrompt(csid, n, dbId) !== null;","tryCatchPattern":null,"preventionTips":["Ensure the worker is spawned and ready before ingestion hooks run (pre-warm the daemon).","On cold boot, allow a small settle delay or retry before treating a missing user_prompts row as authoritative.","Monitor warning frequency per session — occasional on cold boot is expected, persistent means the session-init hook is failing."],"tags":["privacy","race-condition","user-prompts","worker-boot","claude-mem"],"backgroundTag":"startup-race-condition","analyzedSha":"e2d1df569a8f04075d40e92461128ece7cf04c82","analyzedAt":"2026-08-20T23:58:13.836Z","contentChangedAt":"2026-08-20T23:58:13.836Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}