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
- Wait for the agent query before enabling actions: gate the calling code on `agent && selectedCompanyId` (e.g. disable buttons until loaded).
- 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.
- Check that the agent id in the route is valid and that the agent query key includes the correct selectedCompanyId/company scoping.
- 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
- Gate all agent-dependent actions on the agent query's isSuccess state
- Include agent id validity in the route's loader so the page never renders actions without it
- Disable or hide chat actions while agent is undefined
- Redirect to a not-found page when the agent query returns nothing
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
- Discard is unavailable.
- Review unavailable
- Review unavailable
- Select an organization to test adapter environment
- Steering is unavailable.
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)