fix(editor): Gracefully handle expired confirmations in setup wizard#28471
Open
fix(editor): Gracefully handle expired confirmations in setup wizard#28471
Conversation
When the backend sweeps a suspended run after the 10-minute timeout, clicking "Later" or "Continue" on the setup wizard would POST to a 404 endpoint, show a cryptic "Confirmation failed" toast, and leave the UI permanently stuck. - Detect 404 in confirmAction() and return true (run is already gone, let callers proceed with cleanup instead of getting stuck) - Add isConfirmationGone() helper to check if a tool call's run was already cancelled via SSE - Guard handleApply/handleTestTrigger against waiting 60s for a tool result that will never arrive from a cancelled run - Guard credential setup handleContinue to show deferred state when the run was swept
Bundle ReportChanges will increase total bundle size by 695 bytes (0.0%) ⬆️. This is within the configured threshold ✅ Detailed changes
Affected Assets, Files, and Routes:view changes for bundle: editor-ui-esmAssets Changed:
Files in
Files in
|
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
Contributor
There was a problem hiding this comment.
2 issues found across 3 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/frontend/editor-ui/src/features/ai/instanceAi/components/InstanceAiCredentialSetup.vue">
<violation number="1" location="packages/frontend/editor-ui/src/features/ai/instanceAi/components/InstanceAiCredentialSetup.vue:284">
P2: `handleContinue()` can still resolve expired confirmations as `approved` when 404 is returned before SSE updates local `isLoading` state.</violation>
</file>
<file name="packages/frontend/editor-ui/src/features/ai/instanceAi/composables/useSetupActions.ts">
<violation number="1" location="packages/frontend/editor-ui/src/features/ai/instanceAi/composables/useSetupActions.ts:193">
P2: The new `isConfirmationGone()` early return can misclassify completed confirmations as deferred, causing successful apply/test-trigger results to be dropped.</violation>
</file>
Architecture diagram
sequenceDiagram
participant User
participant UI as Setup Wizard (Vue)
participant Logic as useSetupActions (Composable)
participant Store as Instance AI Store
participant API as Backend API
participant SSE as SSE Stream
Note over User, API: Scenario: User acts on a Confirmation that has expired (>10m)
User->>UI: Click "Continue" or "Later"
UI->>Store: confirmAction(requestId, credentials)
Store->>API: POST /confirm
alt Run Expired (Timeout)
API-->>Store: 404 Not Found
Store->>Store: CHANGED: Catch 404 and return true (suppress error toast)
else Success
API-->>Store: 200 OK
end
Store-->>UI: return success (true)
Note over UI, Logic: Post-confirmation flow handles potential "Race Condition"
UI->>Store: NEW: isConfirmationGone(requestId)
Store->>Store: Check tool call isLoading state
opt SSE Update (Concurrent)
SSE->>Store: event: run-finish (status: cancelled)
Store->>Store: Set toolCall.isLoading = false
end
Store-->>UI: return isGone (true)
alt NEW: Run was swept/gone
UI->>UI: Set state to "Deferred"
UI->>Store: resolveConfirmation(requestId, 'deferred')
Note right of UI: UI dismisses gracefully instead of sticking
else Run still active
UI->>Store: resolveConfirmation(requestId, 'approved')
Logic->>Store: NEW: isConfirmationGone(requestId)
alt Run not gone
Logic->>Logic: waitForToolResult()
else Run gone during wait
Logic->>Logic: Graceful exit (skip 60s timeout)
end
end
Note over UI, API: Final state: Wizard closes without "Confirmation failed" error
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.
packages/frontend/editor-ui/src/features/ai/instanceAi/components/InstanceAiCredentialSetup.vue
Outdated
Show resolved
Hide resolved
packages/frontend/editor-ui/src/features/ai/instanceAi/composables/useSetupActions.ts
Outdated
Show resolved
Hide resolved
… store state Replace racy isConfirmationGone() store check with a direct 'expired' return value from confirmAction(), eliminating the race condition between API response and SSE state updates.
Contributor
Performance ComparisonComparing current → latest master → 14-day baseline docker-stats
Memory consumption baseline with starter plan resources
Idle baseline with Instance AI module loaded
How to read this table
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
When the Instance AI setup wizard has been open for >10 minutes, the backend sweeps the suspended run (confirmation timeout). If the user then clicks "Later" or "Continue":
confirmAction()catches it generically → shows cryptic "Confirmation failed" toast → UI stays permanently stuck (buttons do nothing)What changed
confirmAction()ininstanceAi.store.ts: DetectResponseErrorwithhttpStatusCode === 404and returntrueinstead offalse(suppressing the error toast). This lets callers proceed with their cleanup path. Uses the sameerror instanceof ResponseErrorpattern already established insendMessage()(line 787).isConfirmationGone()helper: Checks if a tool call'sisLoadingisfalse(meaning the run was already cancelled via the SSErun-finishevent). This preventshandleApply()andhandleTestTrigger()from waiting 60 seconds for a tool result that will never arrive from a cancelled run.useSetupActions.ts:handleApply()andhandleTestTrigger()checkisConfirmationGone()afterconfirmActionreturnstrue, and gracefully dismiss instead of entering the dead wait.InstanceAiCredentialSetup.vue:handleContinue()checksisConfirmationGone()and shows "Deferred" state instead of "Approved" when the run was swept.Why this works
The backend already sends a
run-finishSSE event withstatus: 'cancelled'when it sweeps an expired run. The frontend reducer setstc.isLoading = false, which removes the confirmation from the panel. The bug only occurs in the race where the user clicks before the SSE event arrives — this fix handles that race by treating the 404 as "effectively handled."Linear tickets
Fixes https://linear.app/n8n/issue/AI-2367 — "Later" doesn't work after waiting
Fixes https://linear.app/n8n/issue/AI-2371 — Cryptic "Confirmation failed" error on Continue
I have seen this code, I have run this code, and I take responsibility for this code.