paperclipai/paperclip · error

companyId is required

Error message

companyId is required

What it means

HTTP 400 from the tool-gateway approve endpoint when neither body.companyId nor ?companyId= supplies a company id. The endpoint needs the company scope for the authorization check and the gateway call.

Source

Thrown at server/src/routes/tool-gateway.ts:592

        approvedActionRequestId:
          typeof body.approvedActionRequestId === "string" ? body.approvedActionRequestId : null,
        idempotencyKey: typeof body.idempotencyKey === "string" ? body.idempotencyKey : null,
        callerHeaders: callerHeaders(req),
      });
      res.json(result);
    } catch (err) {
      sendGatewayError(res, err);
    }
  });

  router.post("/tool-gateway/action-requests/:id/approve", async (req, res) => {
    try {
      assertBoard(req);
      const body = (req.body ?? {}) as { companyId?: string; rememberAction?: boolean };
      if (body.rememberAction !== undefined && typeof body.rememberAction !== "boolean") { res.status(400).json({ error: "rememberAction must be a boolean" }); return; }
      const companyId = body.companyId ?? (typeof req.query.companyId === "string" ? req.query.companyId : null);
      if (!companyId) {
        res.status(400).json({ error: "companyId is required" });
        return;
      }
      assertBoardMutationAccess(req, companyId);
      const actor = getActorInfo(req);
      const actionRequest = await toolGateway.approveActionRequest({
        companyId,
        actionRequestId: req.params.id,
        rememberAction: body.rememberAction,
        actor: {
          agentId: actor.agentId,
          userId: req.actor.type === "board" ? req.actor.userId : null,
        },
      });
      res.json(actionRequest);
    } catch (err) {
      sendGatewayError(res, err);
    }
  });

View on GitHub (pinned to 01ad858492)

Solutions

  1. Include companyId in the JSON body: {"companyId": "..."}.
  2. Or append ?companyId=... to the request URL.
  3. Ensure the calling UI/SDK passes the currently selected company context.
  4. Check that the body is sent with application/json so req.body parses (an unparsed body makes body.companyId undefined).

Example fix

// before
POST /api/tool-gateway/action-requests/ar1/approve  {}
// 400 companyId is required
// after
POST /api/tool-gateway/action-requests/ar1/approve  {"companyId":"c1"}
Defensive patterns

Strategy: validation

Validate before calling

if (!companyId || typeof companyId !== 'string') throw new Error('companyId is required to approve a tool-gateway action request');

Type guard

const hasCompanyId = (b) => typeof b?.companyId === 'string' && b.companyId.length > 0;

Try / catch

try {
  return await approveActionRequest({ actionRequestId, companyId });
} catch (e) {
  if (e.status === 400 && /companyId/.test(e.body?.error ?? '')) {
    throw new Error('configure the active company in the client before approving actions');
  }
  throw e;
}

Prevention

When it happens

Trigger: POST /api/tool-gateway/action-requests/:id/approve with an empty body and no companyId query parameter — companyId resolves to null.

Common situations: Client relies on a company context header the route doesn't read; calling from scripts/tests without tenant context; multi-tenant UI forgetting to pass the selected company.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10). Data as JSON: /api/errors/19ce1abefd345fc7. Report an issue: GitHub.