paperclipai/paperclip · error · HttpError

forbidden

forbidden

Error message

Agents cannot force-release pipeline leases

What it means

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.

Source

Thrown at server/src/routes/pipelines.ts:1825

    const actor = actorForMutation(req);
    const updated = await svc.patchCaseContent({ companyId, caseId, ...req.body, actor });
    res.json(updated);
  });

  router.post("/cases/:caseId/claim", validate(claimCaseSchema), async (req, res) => {
    const caseId = req.params.caseId as string;
    const companyId = await assertCaseAccess(db, req, caseId);
    const actor = actorForMutation(req);
    if (actor.type === "system") throw forbidden();
    const claimed = await svc.claimCase({ companyId, caseId, actor, leaseMs: req.body.leaseSeconds ? req.body.leaseSeconds * 1000 : undefined });
    res.json({ case: claimed, leaseToken: claimed.leaseToken, leaseExpiresAt: claimed.leaseExpiresAt });
  });

  router.post("/cases/:caseId/release", validate(releaseCaseSchema), async (req, res) => {
    const caseId = req.params.caseId as string;
    const companyId = await assertCaseAccess(db, req, caseId);
    const actor = actorForMutation(req);
    if (req.body.force && actor.type === "agent") throw new HttpError(403, "Agents cannot force-release pipeline leases", { code: "forbidden" });
    res.json(await svc.releaseCase({ companyId, caseId, actor, leaseToken: req.body.leaseToken, force: req.body.force }));
  });

  router.post("/cases/:caseId/transition", validate(transitionCaseSchema), async (req, res) => {
    const caseId = req.params.caseId as string;
    const companyId = await assertCaseAccess(db, req, caseId);
    const actor = actorForMutation(req);
    res.json(await svc.transitionCase({
      companyId,
      caseId,
      toStageKey: req.body.toStageKey,
      expectedVersion: req.body.expectedVersion,
      leaseToken: req.body.leaseToken,
      reason: req.body.reason,
      force: req.body.force,
      suggestionId: req.body.acceptSuggestionId,
      actor,
    }));

View on GitHub (pinned to 01ad858492)

Solutions

  1. Perform the force-release as a board user instead of an agent API key.
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at server/src/routes/pipelines.ts:1940 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-08-18). Data as JSON: /api/errors/827f91974e363205. Report an issue: GitHub.