paperclipai/paperclip · error · Error

Agent not found

Error message

Agent not found

What it means

AgentChat throws 'Agent not found' when the ensureIssue callback is invoked before an agent has been resolved for the current chat context. The page fetches the agent asynchronously; if the user action (or query) runs while `agent` is still undefined, or after it fails to load for the selected company, the guard `if (!agent || !selectedCompanyId)` throws. It is a local client-side guard, not a server 404 — it means the UI's agent data has not been resolved yet.

Solutions

  1. Wait for the agent query before enabling actions: gate the calling code on `agent && selectedCompanyId` (e.g. disable buttons until loaded).
  2. Return an early result or skip the call instead of throwing when `agent` is undefined, e.g. `if (!agent || !selectedCompanyId) return;` where a thrown value is unnecessary.
  3. Check that the agent id in the route is valid and that the agent query key includes the correct selectedCompanyId/company scoping.
  4. If the agent truly does not exist, show a not-found state and redirect the user instead of surfacing the raw Error.

Example fix

// before
const ensureIssue = useCallback(async () => {
  if (!agent || !selectedCompanyId) throw new Error("Agent not found");
  ...
}, []);

// after
const ensureIssue = useCallback(async () => {
  if (!agent || !selectedCompanyId) return null; // caller handles null
  ...
}, [agent?.id, selectedCompanyId]);
Defensive patterns

Strategy: validation

Validate before calling

if (!agent || !selectedCompanyId) return; // skip the call until data resolves

Type guard

const isAgentReady = (a: Agent | null | undefined, c: string | null | undefined): a is Agent => Boolean(a?.id && c);

Try / catch

try {
  await ensureIssue();
} catch (err) {
  if (err instanceof Error && err.message === "Agent not found") {
    showError("Chat is still initializing — try again in a moment.");
  } else { throw err; }
}

Prevention

When it happens

Trigger: Calling `ensureIssue()` (directly or via chat creation/recordAgentChatVisit flows) while the agent query is still loading; navigating to an agent chat URL whose agent id does not exist or belongs to another company so the query resolves with no agent; selectedCompanyId is unset when the effect fires.

Common situations: Developer opens AgentChat with a stale or bookmarked agent id; company switcher changes selectedCompanyId before the agent refetch completes; a component callback (attachment, message send) fires during initial render when agent is undefined; deleted agent referenced by an old URL.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


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

Appendix: source

Thrown at ui/src/pages/AgentChat.tsx:49

  const agent = agents.data?.find(
    (item) => item.id === agentRef || agentRouteRef(item) === agentRef,
  );
  const chatKey = queryKeys.agentChats.detail(selectedCompanyId, userId, agent?.id);
  const chat = useQuery({
    queryKey: chatKey,
    queryFn: () => agentChatsApi.get(selectedCompanyId!, agent!.id),
    enabled: enabled && !!agent && session.isFetched,
  });
  const creating = useRef<Promise<Issue> | null>(null);
  useEffect(() => {
    creating.current = null;
  }, [selectedCompanyId, userId, agent?.id]);
  useEffect(() => {
    if (enabled && agent && session.isFetched)
      recordAgentChatVisit(agent.companyId, userId, agent.id);
  }, [enabled, agent?.id, agent?.companyId, userId, session.isFetched]);
  const ensureIssue = useCallback(async () => {
    if (!agent || !selectedCompanyId) throw new Error("Agent not found");
    if (chat.data) return chat.data;
    const promise = (creating.current ??= agentChatsApi.ensure(
      selectedCompanyId,
      agent.id,
    ));
    try {
      const issue = await promise;
      client.setQueryData(queryKeys.issues.detail(issue.id), issue);
      client.setQueryData(chatKey, issue);
      return issue;
    } catch (error) {
      creating.current = null;
      throw error;
    }
  }, [agent, selectedCompanyId, chat.data, client, userId]);
  if (!loaded || agents.isPending || session.isPending)
    return (
      <p className="text-sm text-muted-foreground">Loading conversation…</p>

View on GitHub (pinned to 3f1d897a7c)