{"record":{"id":"435ab698d3aaa133","repo":"paperclipai/paperclip","slug":"cheap-status-only-recovery-runs-cannot-create-or-m-435ab6","errorCode":null,"errorMessage":"Cheap status-only recovery runs cannot create or modify approvals","messagePattern":"Cheap status-only recovery runs cannot create or modify approvals","errorType":"http","errorClass":null,"httpStatus":403,"severity":"error","filePath":"server/src/routes/issues.ts","lineNumber":5112,"sourceCode":"  function isStatusOnlyRecoveryContext(contextSnapshot: unknown) {\n    if (!contextSnapshot || typeof contextSnapshot !== \"object\" || Array.isArray(contextSnapshot)) return false;\n    const context = contextSnapshot as Record<string, unknown>;\n    return context.recoveryIntent === \"status_only\" &&\n      context.allowDeliverableWork === false &&\n      context.allowDocumentUpdates === false &&\n      context.resumeRequiresNormalModel === true;\n  }\n\n  async function loadActorRunContext(req: Request, companyId: string) {\n    if (req.actor.type !== \"agent\") return null;\n    const runId = req.actor.runId?.trim();\n    if (!runId) return null;\n    const run = await db\n      .select({\n        id: heartbeatRuns.id,\n        companyId: heartbeatRuns.companyId,\n        agentId: heartbeatRuns.agentId,\n        contextSnapshot: heartbeatRuns.contextSnapshot,\n      })\n      .from(heartbeatRuns)\n      .where(eq(heartbeatRuns.id, runId))\n      .then((rows) => rows[0] ?? null);\n    if (!run || run.companyId !== companyId || run.agentId !== req.actor.agentId) return null;\n    return run;\n  }\n\n  function readObject(value: unknown): Record<string, unknown> {\n    return value && typeof value === \"object\" && !Array.isArray(value)\n      ? value as Record<string, unknown>\n      : {};\n  }\n\n  async function deriveRecoveryCommentPresentation(\n    req: Request,\n    companyId: string,\n    body: string,","sourceCodeStart":5094,"sourceCodeEnd":5130,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/routes/issues.ts#L5094-L5130","documentation":"403 from assertApprovalMutationAllowedByRunContext: the actor's run is a cheap, status-only recovery run, and such runs are explicitly barred from creating or modifying approvals; resuming requires a normal-model run.","triggerScenarios":"Thrown at server/src/routes/issues.ts:4957 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["This is an authorization rule, not a bug: perform the action with an actor that satisfies the stated constraint (board user, the owning agent, or an in-scope resource).","If access should be allowed, verify the actor's credentials/company scope and the resource's ownership before retrying."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-08-18T22:49:45.177Z","contentChangedAt":"2026-08-18T22:49:45.177Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}