{"record":{"id":"c15a80345b09c5ff","repo":"thedotmack/claude-mem","slug":"generation-job-job-id-not-found-in-scope","errorCode":null,"errorMessage":"generation job ${job.id} not found in scope","messagePattern":"generation job (.+?) not found in scope","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/server/generation/processGeneratedResponse.ts","lineNumber":254,"sourceCode":"): Promise<ProcessGeneratedResponseOutcome> {\n  const { job } = input;\n\n  return withPostgresTransaction(input.pool, async (client) => {\n    const obsRepo = new PostgresObservationRepository(client);\n    const sourcesRepo = new PostgresObservationSourcesRepository(client);\n    const jobsRepo = new PostgresObservationGenerationJobRepository(client);\n    const eventsLogRepo = new PostgresObservationGenerationJobEventsRepository(client);\n    const auditRepo = new PostgresAuthRepository(client);\n\n    // Reload the job inside the transaction. If it was already completed\n    // by another worker, return its existing observations idempotently.\n    const fresh = await jobsRepo.getByIdForScope({\n      id: job.id,\n      projectId: job.projectId,\n      teamId: job.teamId,\n    });\n    if (!fresh) {\n      throw new Error(`generation job ${job.id} not found in scope`);\n    }\n    if (fresh.status === 'completed' || fresh.status === 'cancelled' || fresh.status === 'failed') {\n      logger.info('SYSTEM', 'generation job already in terminal status; skipping persistence', {\n        jobId: fresh.id,\n        status: fresh.status,\n      });\n      return {\n        kind: 'completed' as const,\n        jobId: fresh.id,\n        observations: [],\n        privateContentDetected,\n      };\n    }\n\n    const persisted: PostgresObservation[] = [];\n    for (let index = 0; index < rendered.length; index++) {\n      const { kind, content, metadata } = rendered[index]!;\n      if (!content || content.trim().length === 0) {","sourceCodeStart":236,"sourceCodeEnd":272,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/e2d1df569a8f04075d40e92461128ece7cf04c82/src/server/generation/processGeneratedResponse.ts#L236-L272","documentation":"Twin of the FOLDER_MD_EXCLUDE parse failure: the #2400 skeleton deny-list setting CLAUDE_MEM_FOLDER_MD_SKELETON_DENYLIST must be a JSON array of glob strings ('[]' default). JSON.parse threw and the code warns, leaving skeletonDenylistPatterns empty — meaning empty/skeleton CLAUDE.md files will be injected in folders the user meant to suppress (the deny-list only suppresses injection when generated content is empty; active folders still get their CLAUDE.md).","triggerScenarios":"Setting the deny-list as comma-separated text instead of a JSON array; quoting mistakes in shell profiles or CI variables; smart-quote copy-paste from rendered docs.","commonSituations":"Hardcoding per-machine overrides after reading issue #2400; monorepo configs where the env var passes through several layers of quoting.","solutions":["Set the value as a JSON array: CLAUDE_MEM_FOLDER_MD_SKELETON_DENYLIST=[\"packages/fixtures\",\"examples\"]","Round-trip check: `node -e 'JSON.parse(process.argv[1])' \"$CLAUDE_MEM_FOLDER_MD_SKELETON_DENYLIST\"`.","Remove the variable entirely if you want the default empty deny-list.","Check the sibling CLAUDE_MEM_FOLDER_MD_EXCLUDE too — the same edit mistake usually breaks both."],"exampleFix":"# before\nCLAUDE_MEM_FOLDER_MD_SKELETON_DENYLIST=packages/fixtures,examples\n\n# after\nCLAUDE_MEM_FOLDER_MD_SKELETON_DENYLIST=[\"packages/fixtures\",\"examples\"]","handlingStrategy":"validation","validationCode":"function parseJsonStringArray(raw: string | undefined, name: string): string[] {\n  if (!raw) return [];\n  try {\n    const parsed: unknown = JSON.parse(raw);\n    if (isStringArray(parsed)) return parsed;\n  } catch { /* fall through */ }\n  throw new Error(`${name} must be a JSON array of strings, got: ${raw}`);\n}\n\nconst denylist = parseJsonStringArray(settings.CLAUDE_MEM_FOLDER_MD_SKELETON_DENYLIST, 'CLAUDE_MEM_FOLDER_MD_SKELETON_DENYLIST');","typeGuard":"function isStringArray(value: unknown): value is string[] {\n  return Array.isArray(value) && value.every(v => typeof v === 'string');\n}","tryCatchPattern":null,"preventionTips":["Use one shared JSON-array parser for every list-shaped setting so both EXCLUDE and DENYLIST fail loudly at config load, not mid-generation.","Validate in CI: fail the build if any CLAUDE_MEM_* list variable is present but not parseable JSON.","Beware docs renderers converting straight quotes to smart quotes when copying example values."],"tags":["settings","json-parse","configuration","claude-md","deny-list"],"backgroundTag":"malformed-json-setting","analyzedSha":"e2d1df569a8f04075d40e92461128ece7cf04c82","analyzedAt":"2026-08-20T23:58:13.836Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}