You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Error: Error invoking remote method 'workflow:list': Error: No handler registered for 'workflow:list' #25
Auto-triage attempted but the candidate fix failed npx tsc. Human review needed. Log: C:\Users\DavidEngelhart\AppData\Local\termpolis\auto-triage\run-20260818-160422.log
This was not a missing handler.workflow:list has been registered since v1.31.0 (src/main/workflow/ipc.ts:119). What was missing was the ordering guarantee: both createWindow() (src/main/index.ts:2715) and registerWorkflowIpc(...) (src/main/index.ts:3554) live inside the same app.whenReady().then(), ~840 lines apart, with several un-awaited async starts (startMemoryHost, pickFreePort) widening the gap. On a cold boot the renderer can therefore mount and call ipcRenderer.invoke('workflow:list') before main has registered the handler.
That is why the auto-triage bot's candidate fix failed npx tsc — it was looking for a handler to add, and there was nothing to add.
Two things made it worse than a transient:
listWorkflows(...) had no .catch, so the rejection became an unhandled promise rejection and went straight to Sentry instead of to the user.
The failure was permanent for the whole session — nothing retried, so the workflow list silently stayed empty until the app was restarted.
Fix (src/renderer/src/components/Sidebar/Sidebar.tsx): a bounded retry on the workflow-loading effect — 5 attempts on a linear backoff spanning 1.5s, which covers the boot gap without making a healthy boot wait on it.
The important detail: it retries only on rejection. An err() response means main is answering and is honoured as an answer, so a healthy main process never gets hammered by a retry loop. That distinction has its own regression test.
I deliberately did not hoist registerWorkflowIpc earlier in whenReady(). This codebase's own comments repeatedly warn that a wiring fault must never fatal whenReady, and reordering boot is the riskiest change available here; a renderer-side retry fixes the same race with a far smaller blast radius.
Tests — 5 new cases in tests/components/Sidebar.test.tsx covering: retry-until-registered, the watcher re-arming on each attempt, the retry budget terminating instead of hammering main forever, err() responses not retrying, and a pending retry being cancelled on unmount.
Activity
codedev-david commentedon Aug 18, 2026
Auto-triage attempted but the candidate fix failed
npx tsc. Human review needed. Log:C:\Users\DavidEngelhart\AppData\Local\termpolis\auto-triage\run-20260818-160422.logv1.41.3: an agent profile can no longer name a shell you do not have
codedev-david commentedon Sep 13, 2026
Fixed in v1.41.3.
This was not a missing handler.
workflow:listhas been registered since v1.31.0 (src/main/workflow/ipc.ts:119). What was missing was the ordering guarantee: bothcreateWindow()(src/main/index.ts:2715) andregisterWorkflowIpc(...)(src/main/index.ts:3554) live inside the sameapp.whenReady().then(), ~840 lines apart, with several un-awaited async starts (startMemoryHost,pickFreePort) widening the gap. On a cold boot the renderer can therefore mount and callipcRenderer.invoke('workflow:list')before main has registered the handler.That is why the auto-triage bot's candidate fix failed
npx tsc— it was looking for a handler to add, and there was nothing to add.Two things made it worse than a transient:
listWorkflows(...)had no.catch, so the rejection became an unhandled promise rejection and went straight to Sentry instead of to the user.Fix (
src/renderer/src/components/Sidebar/Sidebar.tsx): a bounded retry on the workflow-loading effect — 5 attempts on a linear backoff spanning 1.5s, which covers the boot gap without making a healthy boot wait on it.The important detail: it retries only on rejection. An
err()response means main is answering and is honoured as an answer, so a healthy main process never gets hammered by a retry loop. That distinction has its own regression test.I deliberately did not hoist
registerWorkflowIpcearlier inwhenReady(). This codebase's own comments repeatedly warn that a wiring fault must never fatalwhenReady, and reordering boot is the riskiest change available here; a renderer-side retry fixes the same race with a far smaller blast radius.Tests — 5 new cases in
tests/components/Sidebar.test.tsxcovering: retry-until-registered, the watcher re-arming on each attempt, the retry budget terminating instead of hammering main forever,err()responses not retrying, and a pending retry being cancelled on unmount.