paperclipai/paperclip · error

Agent is outside this actor's authorization boundary

Error message

Agent is outside this actor's authorization boundary

What it means

The agents route's access check (assertAgentReadAllowed / access.decide) denied agent:read for the requesting actor: the agent lies outside the actor's authorization boundary (wrong company or insufficient grants). Surfaced as a forbidden/authorization failure.

Solutions

  1. Access only agents within the actor's authorized company scope.
Defensive patterns

Strategy: validation

When it happens

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

Common situations: See trigger scenarios.


AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-08-18). Data as JSON: /api/errors/32c56046c55f6e39. Report an issue: GitHub.

Appendix: source

Thrown at server/src/routes/agents.ts:604

    row.adapterType === identity.adapterType;
  const inMemorySetupTokenCleanupStore: SetupTokenCleanupStore = {
    async record(record): Promise<void> {
      setupTokenCleanupRows.set(record.sessionId, { ...record });
    },
    async markState(identity, state): Promise<void> {
      const row = setupTokenCleanupRows.get(identity.sessionId);
      if (row && scopeMatchesRow(row, identity)) row.state = state;
    },
    async remove(identity): Promise<void> {
      // The delete matches the full owner scope, so it never removes a row by the
      // session id alone.
      const row = setupTokenCleanupRows.get(identity.sessionId);
      if (row && scopeMatchesRow(row, identity)) setupTokenCleanupRows.delete(identity.sessionId);
    },
    async listReapable(): Promise<SetupTokenCleanupRecord[]> {
      return [];
    },
    async consumeStoredClaim(identity): Promise<SetupTokenCleanupRecord | null> {
      const row = setupTokenCleanupRows.get(identity.sessionId);
      if (
        !row ||
        !scopeMatchesRow(row, identity) ||
        row.state !== "stored" ||
        row.boundAt !== null ||
        row.deadline <= Date.now()
      ) {
        return null;
      }
      row.boundAt = Date.now();
      return { ...row };
    },
    async cancelDurable(identity, cancellableStates): Promise<SetupTokenCleanupRecord | null> {
      const row = setupTokenCleanupRows.get(identity.sessionId);
      if (!row || !scopeMatchesRow(row, identity) || !cancellableStates.includes(row.state)) {
        return null;
      }

View on GitHub (pinned to 3f1d897a7c)