{"record":{"id":"827f91974e363205","repo":"paperclipai/paperclip","slug":"forbidden","errorCode":"forbidden","errorMessage":"Agents cannot force-release pipeline leases","messagePattern":"Agents cannot force-release pipeline leases","errorType":"http","errorClass":"HttpError","httpStatus":403,"severity":"error","filePath":"server/src/routes/pipelines.ts","lineNumber":1825,"sourceCode":"    const actor = actorForMutation(req);\n    const updated = await svc.patchCaseContent({ companyId, caseId, ...req.body, actor });\n    res.json(updated);\n  });\n\n  router.post(\"/cases/:caseId/claim\", validate(claimCaseSchema), async (req, res) => {\n    const caseId = req.params.caseId as string;\n    const companyId = await assertCaseAccess(db, req, caseId);\n    const actor = actorForMutation(req);\n    if (actor.type === \"system\") throw forbidden();\n    const claimed = await svc.claimCase({ companyId, caseId, actor, leaseMs: req.body.leaseSeconds ? req.body.leaseSeconds * 1000 : undefined });\n    res.json({ case: claimed, leaseToken: claimed.leaseToken, leaseExpiresAt: claimed.leaseExpiresAt });\n  });\n\n  router.post(\"/cases/:caseId/release\", validate(releaseCaseSchema), async (req, res) => {\n    const caseId = req.params.caseId as string;\n    const companyId = await assertCaseAccess(db, req, caseId);\n    const actor = actorForMutation(req);\n    if (req.body.force && actor.type === \"agent\") throw new HttpError(403, \"Agents cannot force-release pipeline leases\", { code: \"forbidden\" });\n    res.json(await svc.releaseCase({ companyId, caseId, actor, leaseToken: req.body.leaseToken, force: req.body.force }));\n  });\n\n  router.post(\"/cases/:caseId/transition\", validate(transitionCaseSchema), async (req, res) => {\n    const caseId = req.params.caseId as string;\n    const companyId = await assertCaseAccess(db, req, caseId);\n    const actor = actorForMutation(req);\n    res.json(await svc.transitionCase({\n      companyId,\n      caseId,\n      toStageKey: req.body.toStageKey,\n      expectedVersion: req.body.expectedVersion,\n      leaseToken: req.body.leaseToken,\n      reason: req.body.reason,\n      force: req.body.force,\n      suggestionId: req.body.acceptSuggestionId,\n      actor,\n    }));","sourceCodeStart":1807,"sourceCodeEnd":1843,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/routes/pipelines.ts#L1807-L1843","documentation":"Actor-permission guard on the pipeline lease force-release route: the mutating actor is an agent (not board/user), and force-releasing another holder's pipeline case lease is reserved for human operators. The route rejects the agent's request to preserve lease ownership semantics.","triggerScenarios":"Thrown at server/src/routes/pipelines.ts:1940 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Perform the force-release as a board user instead of an agent API key."],"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-14T05:17:10.506Z"}