paperclipai/paperclip · error · Error

Agent not found: ${agentRef}

Error message

Agent not found: ${agentRef}

What it means

Thrown by resolveAgent (token.ts:222) on the UUID branch: the input matched the UUID regex, GET /api/agents/{uuid} either resolved null OR returned an agent whose companyId does not match the requested company. Enforces company-scoped agent lookup.

Source

Thrown at cli/src/commands/client/token.ts:222

      .argument("<keyId>", "Board API key ID")
      .action(async (keyId: string, opts: BaseClientOptions) => {
        try {
          const ctx = resolveCommandContext(opts);
          const result = await ctx.api.delete<{ ok: true; keyId: string }>(apiPath`/api/board-api-keys/${keyId}`);
          printOutput(result ?? { ok: true, keyId }, { json: ctx.json });
        } catch (err) {
          handleCommandError(err);
        }
      }),
  );
}

async function resolveAgent(api: { get<T>(path: string): Promise<T | null> }, companyId: string, agentRef: string): Promise<Agent> {
  const trimmed = agentRef.trim();
  if (!trimmed) throw new Error("Agent reference is required");
  if (/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(trimmed)) {
    const agent = await api.get<Agent>(apiPath`/api/agents/${trimmed}`);
    if (!agent || agent.companyId !== companyId) throw new Error(`Agent not found: ${agentRef}`);
    return agent;
  }
  const query = new URLSearchParams({ companyId });
  const agent = await api.get<Agent>(`${apiPath`/api/agents/${trimmed}`}?${query.toString()}`);
  if (!agent || agent.companyId !== companyId) throw new Error(`Agent not found: ${agentRef}`);
  return agent;
}

function resolveBoardKeyExpiresAt(opts: BoardTokenOptions): Date | null | undefined {
  if (opts.neverExpires) return null;
  if (opts.expiresAt?.trim()) {
    const date = new Date(opts.expiresAt.trim());
    if (!Number.isFinite(date.getTime())) throw new Error(`Invalid --expires-at value: ${opts.expiresAt}`);
    return date;
  }
  if (opts.ttlDays?.trim()) {
    const days = Number(opts.ttlDays);
    if (!Number.isFinite(days) || days <= 0) throw new Error(`Invalid --ttl-days value: ${opts.ttlDays}`);

View on GitHub (pinned to 67001ec6eb)

Solutions

  1. Confirm the UUID belongs to the given --company-id via the board UI or GET /api/agents?companyId=...
  2. Re-fetch the agent list for the correct company and copy the current UUID.
  3. If the agent was deleted, recreate it or use its successor.

Example fix

// before
--company-id companyA --agent <uuid-from-companyB>
// after
--company-id companyB --agent <same-uuid>
Defensive patterns

Strategy: try-catch

Validate before calling

const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
async function findAgentInCompany(api, companyId: string, uuid: string) {
  if (!UUID_RE.test(uuid)) return null;
  const agent = await api.get<Agent>(`/api/agents/${uuid}`);
  return agent && agent.companyId === companyId ? agent : null;
}

Type guard

function isUuidBelongingToCompany(agent: Agent | null, companyId: string): agent is Agent {
  return !!agent && agent.companyId === companyId;
}

Try / catch

try {
  const agent = await resolveAgent(ctx.api, companyId, agentRef);
} catch (err) {
  if (err instanceof Error && err.message.startsWith("Agent not found")) {
    console.error(`Agent ${agentRef} is missing or not in company ${companyId}.`);
  }
  throw err;
}

Prevention

When it happens

Trigger: Passing a syntactically valid UUID that does not exist, exists in a different company, or belongs to no company. The company boundary check (`agent.companyId !== companyId`) rejects cross-company agent references.

Common situations: Copy-pasting an agent UUID from another company, stale UUID after an agent was deleted/recreated, or a wrong --company-id that does not own the agent.

Related errors


AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12). Data as JSON: /api/errors/6e96f3281e408ff8. Report an issue: GitHub.