{"record":{"id":"c2fb93a491936d61","repo":"paperclipai/paperclip","slug":"run-not-found","errorCode":"run_not_found","errorMessage":"Heartbeat run not found","messagePattern":"Heartbeat run not found","errorType":"error_code","errorClass":"WatchdogDecisionApplicationError","httpStatus":null,"severity":"error","filePath":"server/src/modules/active-run-watchdog/application/use-cases.ts","lineNumber":137,"sourceCode":"\nexport type RecordWatchdogDecisionUseCaseInput = {\n  companyId: string;\n  runId: string;\n  actor: WatchdogDecisionActor;\n  decision: \"snooze\" | \"continue\" | \"dismissed_false_positive\";\n  evaluationIssueId?: string | null;\n  reason?: string | null;\n  snoozedUntil?: Date | null;\n  createdByRunId?: string | null;\n  now?: Date;\n};\n\nexport function createRecordWatchdogDecision(deps: RecordWatchdogDecisionDeps) {\n  return async function recordWatchdogDecision(\n    input: RecordWatchdogDecisionUseCaseInput,\n  ): Promise<WatchdogDecisionRecord> {\n    const run = await deps.reader.findRunForCompany(input.companyId, input.runId);\n    if (!run) throw new WatchdogDecisionApplicationError(\"run_not_found\", \"Heartbeat run not found\");\n\n    const evaluationIssue = input.evaluationIssueId\n      ? await deps.reader.findEvaluationIssueById(input.companyId, input.evaluationIssueId)\n      : null;\n    if (input.evaluationIssueId && !evaluationIssue) {\n      throw new WatchdogDecisionApplicationError(\"evaluation_issue_not_found\", \"Evaluation issue not found\");\n    }\n    if (input.actor.type === \"agent\" && !evaluationIssue) {\n      throw new WatchdogDecisionApplicationError(\n        \"evaluation_issue_required\",\n        \"Agent watchdog decisions require the target evaluation issue\",\n      );\n    }\n\n    const boardActor = input.actor.type === \"board\";\n    const assignedRecoveryOwner =\n      input.actor.type === \"agent\" &&\n      Boolean(input.actor.agentId) &&","sourceCodeStart":119,"sourceCodeEnd":155,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/modules/active-run-watchdog/application/use-cases.ts#L119-L155","documentation":"createRecordWatchdogDecision looks up the heartbeat run with reader.findRunForCompany(companyId, runId); when no run matches — including runs that exist but belong to a different company — it throws WatchdogDecisionApplicationError with code run_not_found. This is a company-scoped not-found guard for recording watchdog decisions on active-run (heartbeat) runs.","triggerScenarios":"Calling recordWatchdogDecision (via the active-run-watchdog API or createActiveRunWatchdog wiring) with a runId that does not exist, was deleted, is mistyped, or exists under a different companyId so the company-scoped query returns nothing.","commonSituations":"Clients caching run IDs from a different company context; decisions recorded after the heartbeat run was purged; UUID truncated/transformed by a proxy; passing a heartbeat ID vs run ID confusion between tables.","solutions":["Verify the runId exists in the heartbeat runs table and belongs to the same companyId in the request context","Re-fetch the current run list for the company to confirm the ID is still valid before recording a decision","Check for cross-company context leakage: confirm the authenticated actor's companyId matches the run's company","If the run was deleted legitimately, treat the decision as obsolete instead of retrying"],"exampleFix":"// before\nawait recordWatchdogDecision({ companyId: otherCompanyId, runId: cachedRunId, ... });\n// after\nconst runs = await listHeartbeatRuns(companyId);\nconst run = runs.find(r => r.id === runId);\nif (!run) throw new Error('run not found in company; refetch before recording decision');\nawait recordWatchdogDecision({ companyId, runId: run.id, ... });","handlingStrategy":"validation","validationCode":"const run = await listHeartbeatRuns(companyId).then(rs => rs.find(r => r.id === runId)); if (!run) throw new Error(`run ${runId} not found for company ${companyId}`);","typeGuard":"null","tryCatchPattern":"try { await recordWatchdogDecision(input); } catch (e) { if (e.code === 'run_not_found') { /* refetch run list; abort decision as obsolete */ } else throw e; }","preventionTips":["Always resolve run IDs from a company-scoped query in the same request context","Do not cache heartbeat run IDs across company switches or long-lived automation","Confirm ID integrity end-to-end (no proxy truncation/rewriting)"],"tags":["not-found","watchdog","company-scope","heartbeat"],"backgroundTag":"record-not-found","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}