{"record":{"id":"354062279cac4829","repo":"paperclipai/paperclip","slug":"native-runtime-run-missing","errorCode":"native_runtime_run_missing","errorMessage":"native_runtime_run_missing","messagePattern":"native_runtime_run_missing","errorType":"error_code","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"server/src/services/native-runtime/prepare-native-run.ts","lineNumber":110,"sourceCode":"      db: input.db,\n      companyId: input.run.companyId,\n      issue: input.issue,\n      actorId: input.run.agentId,\n    });\n  const binding = contractBinding(completion.contract, completion.row.revision);\n\n  await input.db.transaction(async (tx) => {\n    const [locked] = await tx\n      .select()\n      .from(heartbeatRuns)\n      .where(and(\n        eq(heartbeatRuns.id, input.run.id),\n        eq(heartbeatRuns.companyId, input.run.companyId),\n        eq(heartbeatRuns.agentId, input.run.agentId),\n      ))\n      .for(\"update\")\n      .limit(1);\n    if (!locked) throw new Error(\"native_runtime_run_missing\");\n    if (locked.runtimeModeResolvedAt && locked.runtimeMode !== \"native\") {\n      throw new Error(\"native_runtime_mode_conflict\");\n    }\n    if (\n      locked.runtimeModeResolvedAt\n      && (\n        locked.runnerInstanceId !== runnerInstanceId\n        || locked.nativeSessionId !== normalizedSessionId\n        || locked.nativeIssueId !== input.issue.id\n        || locked.completionContractId !== completion.row.id\n      )\n    ) {\n      throw new Error(\"native_runtime_binding_conflict\");\n    }\n    await tx\n      .update(heartbeatRuns)\n      .set({\n        runtimeMode: \"native\",","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/server/src/services/native-runtime/prepare-native-run.ts#L92-L128","documentation":"prepareNativeHeartbeatRun locks the heartbeat run row (SELECT ... FOR UPDATE) scoped by id, companyId, and agentId before preparing a native runtime run. If no row matches all three predicates, it throws 'native_runtime_run_missing'. This guards against preparing a run that was deleted, belongs to a different company/agent, or was never created.","triggerScenarios":"Calling prepareNativeHeartbeatRun with input.run.id that does not exist, or where the run's companyId or agentId does not match input.run.companyId/input.run.agentId. Reached via seedPreparedChatRecovery, the native recovery path, or resumedNative recovery.","commonSituations":"Stale run reference passed into recovery after the run row was deleted or a DB reset; cross-company or cross-agent run IDs supplied by buggy seeding code; retried recovery for a run already purged.","solutions":["Verify the heartbeat run row exists: SELECT * FROM heartbeat_runs WHERE id = <run.id> AND company_id = <companyId> AND agent_id = <agentId>.","Check that the caller (seedPreparedChatRecovery / native / resumedNative recovery) passes run id, companyId, and agentId from the same originating row, not remapped values.","If the run was legitimately deleted, skip or recreate the run instead of retrying recovery for the stale reference.","After a dev DB reset (rm -rf data/pglite), discard persisted run references from before the reset."],"exampleFix":"// before\nawait prepareNativeHeartbeatRun({ run: { id: staleRunId, companyId: otherCompany, agentId } });\n// after\nconst [row] = await db.select().from(heartbeatRuns).where(eq(heartbeatRuns.id, runId)).limit(1);\nif (!row) return; // run no longer exists; skip recovery\nawait prepareNativeHeartbeatRun({ run: { id: row.id, companyId: row.companyId, agentId: row.agentId } });","handlingStrategy":"validation","validationCode":"const exists = await db.select({ id: heartbeatRuns.id }).from(heartbeatRuns).where(and(eq(heartbeatRuns.id, run.id), eq(heartbeatRuns.companyId, run.companyId), eq(heartbeatRuns.agentId, run.agentId))).limit(1);\nif (exists.length === 0) throw new SkipRecoveryError(run.id);","typeGuard":"function runRowMatches(row, run) { return !!row && row.id === run.id && row.companyId === run.companyId && row.agentId === run.agentId; }","tryCatchPattern":"try {\n  await prepareNativeHeartbeatRun({ run });\n} catch (e) {\n  if (e.message === \"native_runtime_run_missing\") return; // skip stale run\n  throw e;\n}","preventionTips":["Always source run.id/companyId/agentId from the same fetched row, never from mixed inputs.","Treat run references as ephemeral: revalidate existence before recovery after restarts or DB resets.","Log the run id on failure so stale references are diagnosable."],"tags":["database","concurrency","record-missing"],"backgroundTag":"record-not-found","analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-09-18T08:03:59.046Z","contentChangedAt":"2026-09-18T08:03:59.046Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}