Problem
AgentsSection fires Promise.all(ids.map((id) => fetchAgentMeta(id))) inside a useEffect with no await and no .catch. fetchAgentMeta itself contains await window.clawwork.listAgentFiles(...) without a try/catch — if that IPC throws, two things break:
- The unhandled promise rejection propagates out of the
Promise.all and becomes a renderer-wide console error (or crashes the tab in strict settings).
setLoadingFilesFor(null) is never called, so the agent stays in "loading files" state indefinitely with no way to recover short of switching gateways.
Location
File: packages/desktop/src/renderer/layouts/Settings/sections/AgentsSection.tsx:751-755 (caller) and 698-713 (callee)
// Caller
useEffect(() => {
if (!selectedGatewayId || agents.length === 0) return;
const ids = agents.map((a) => a.id);
Promise.all(ids.map((id) => fetchAgentMeta(id))); // no await, no catch
}, [selectedGatewayId, agents, fetchAgentMeta]);
// Callee
const fetchAgentMeta = useCallback(
async (agentId: string) => {
if (!selectedGatewayId) return;
setLoadingFilesFor(agentId);
const res = await window.clawwork.listAgentFiles(selectedGatewayId, agentId); // throw → state leak
setLoadingFilesFor(null);
// ...
},
[selectedGatewayId],
);
Fix Approach
- In
fetchAgentMeta, wrap the IPC in try/finally so setLoadingFilesFor(null) always runs:
setLoadingFilesFor(agentId);
try {
const res = await window.clawwork.listAgentFiles(selectedGatewayId, agentId);
// ... handle result
} catch (err) {
console.error('[AgentsSection] listAgentFiles failed:', err);
} finally {
setLoadingFilesFor((current) => (current === agentId ? null : current));
}
- In the caller
useEffect, attach .catch to the Promise.all so unhandled rejections are logged explicitly.
Verification
- Run
pnpm check — must pass.
- Manual: simulate
listAgentFiles throwing — the agent row should stop showing a loading spinner and the console should log the error.
Context
- WG: UI & Design System
- Priority: Low (good first issue)
- Estimated effort: 15-20 minutes
Problem
AgentsSectionfiresPromise.all(ids.map((id) => fetchAgentMeta(id)))inside auseEffectwith noawaitand no.catch.fetchAgentMetaitself containsawait window.clawwork.listAgentFiles(...)without a try/catch — if that IPC throws, two things break:Promise.alland becomes a renderer-wide console error (or crashes the tab in strict settings).setLoadingFilesFor(null)is never called, so the agent stays in "loading files" state indefinitely with no way to recover short of switching gateways.Location
File:
packages/desktop/src/renderer/layouts/Settings/sections/AgentsSection.tsx:751-755(caller) and698-713(callee)Fix Approach
fetchAgentMeta, wrap the IPC intry/finallysosetLoadingFilesFor(null)always runs:useEffect, attach.catchto thePromise.allso unhandled rejections are logged explicitly.Verification
pnpm check— must pass.listAgentFilesthrowing — the agent row should stop showing a loading spinner and the console should log the error.Context