feat: node-specific error tab with selection-aware grouping and error overlay#8956
feat: node-specific error tab with selection-aware grouping and error overlay#8956christian-byrne merged 19 commits intomainfrom
Conversation
…erlay - Remove TabError.vue; consolidate all error display into TabErrors.vue and remove the separate 'error' tab type from rightSidePanelStore - Single-node selection mode: regroup errors by message instead of class_type and render ErrorNodeCard in compact mode (hiding redundant header/message) - Container node support: detect internal errors in subgraph/group nodes by matching execution ID prefixes against selected container node IDs - SectionWidgets: show error badge and 'See Error' button for subgraph/group nodes that contain child-node errors, navigating directly to the errors tab - Add ErrorOverlay component: floating card after execution failure showing a deduplicated error summary with 'Dismiss' and 'See Errors' actions; 'See Errors' deselects all nodes and opens Errors tab in overview mode - Add isErrorOverlayOpen, showErrorOverlay, dismissErrorOverlay to executionStore; reset overlay state on execution_start
- Add allErrorExecutionIds computed to executionStore to centralize error ID collection from lastNodeErrors and lastExecutionError - Add hasInternalErrorForNode helper to executionStore to encapsulate prefix-based container error detection - Replace duplicated error ID collection and prefix checks in RightSidePanel and SectionWidgets with store computed/helper - Split errorGroups into allErrorGroups (unfiltered) and tabErrorGroups (selection-filtered) in useErrorGroups - Add filterBySelection param (default: false) to addNodeErrorToGroup, processNodeErrors, processExecutionError - Add groupedErrorMessages computed derived from allErrorGroups for deduped message list used by ErrorOverlay - Migrate ErrorOverlay business logic to useErrorGroups composable, removing inline groupedErrors computed and redundant totalErrorCount wrapper
…or navigation & format
|
Playwright: ❌ 526 passed, 2 failed · 2 flaky ❌ Failed Tests📊 Browser Reports
|
🎨 Storybook Build Status✅ Build completed successfully! ⏰ Completed at: 02/20/2026, 08:02:46 PM UTC 🔗 Links🎉 Your Storybook is ready for review! |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds a new ErrorOverlay component mounted in the top menu, extends executionStore with cloud-validation parsing and overlay state, refactors error grouping to be selection- and group-aware, replaces legacy TabError with TabErrors, and updates right-side panel, canvas focusing, and UI gating for the Errors tab. Changes
Sequence DiagramsequenceDiagram
participant Exec as Execution Handler
participant Store as Execution Store
participant Overlay as ErrorOverlay (UI)
participant Panel as RightSidePanel
participant Canvas as Canvas/Litegraph
Exec->>Store: handleExecutionError(detail)
alt Cloud validation error
Store->>Store: handleCloudValidationError(detail)
else Service-level error
Store->>Store: handleServiceLevelError(detail)
end
Store->>Store: update error state (errors, allErrorExecutionIds, totalErrorCount)
opt ShowErrorsTab enabled
Store->>Store: showErrorOverlay()
Store->>Overlay: isErrorOverlayOpen = true
Overlay->>Overlay: render grouped errors via useErrorGroups
alt User clicks "See Errors"
Overlay->>Store: dismissErrorOverlay()
Overlay->>Panel: request open 'errors' tab
Panel->>Canvas: clear selections
Panel->>Panel: render TabErrors (uses useErrorGroups)
else User dismisses
Overlay->>Store: dismissErrorOverlay()
end
end
Panel->>Canvas: focusNode(nodeId, executionIdMap?)
alt Node inside group
Canvas->>Canvas: navigate to parent group, animateToBounds, fitView
else Normal node
Canvas->>Canvas: focus node directly
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Tip Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/scripts/app.ts (1)
73-73:⚠️ Potential issue | 🔴 CriticalRemove unused
useRightSidePanelStoreimport (TS6133).
CI is failing with an unused import after the error-panel logic change.🧹 Suggested fix
-import { useRightSidePanelStore } from '@/stores/workspace/rightSidePanelStore'🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/scripts/app.ts` at line 73, Remove the unused import useRightSidePanelStore from the module: delete the line importing useRightSidePanelStore (or remove it from the import list) so the symbol is not imported anywhere in the file (e.g., the import statement that currently reads "import { useRightSidePanelStore } ..."); ensure no other code in this file references useRightSidePanelStore and run TypeScript/CI to confirm TS6133 is resolved.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/stores/executionStore.ts`:
- Around line 458-484: handleCloudValidationError sets lastPromptError (and
lastNodeErrors) before calling resetExecutionState, but resetExecutionState
clears those values so prompt-level errors disappear; modify
handleCloudValidationError (or reorder calls) so you capture the extracted
prompt error/node errors, call clearInitializationByPromptId and
resetExecutionState first, then assign lastNodeErrors.value or
lastPromptError.value from the previously extracted error object (use
tryExtractValidationError result), ensuring you still return true when handled;
reference function names: handleCloudValidationError, tryExtractValidationError,
clearInitializationByPromptId, resetExecutionState, and variables
lastPromptError / lastNodeErrors.
---
Outside diff comments:
In `@src/scripts/app.ts`:
- Line 73: Remove the unused import useRightSidePanelStore from the module:
delete the line importing useRightSidePanelStore (or remove it from the import
list) so the symbol is not imported anywhere in the file (e.g., the import
statement that currently reads "import { useRightSidePanelStore } ..."); ensure
no other code in this file references useRightSidePanelStore and run
TypeScript/CI to confirm TS6133 is resolved.
📦 Bundle: 4.32 MB gzip 🔴 +2.62 kBDetailsSummary
Category Glance App Entry Points — 21.4 kB (baseline 21.4 kB) • ⚪ 0 BMain entry bundles and manifests
Status: 1 added / 1 removed Graph Workspace — 941 kB (baseline 934 kB) • 🔴 +7.28 kBGraph editor runtime, canvas, workflow orchestration
Status: 1 added / 1 removed Views & Navigation — 68.6 kB (baseline 68.6 kB) • ⚪ 0 BTop-level views, pages, and routed surfaces
Status: 9 added / 9 removed Panels & Settings — 430 kB (baseline 430 kB) • ⚪ 0 BConfiguration panels, inspectors, and settings screens
Status: 10 added / 10 removed User & Accounts — 16 kB (baseline 16 kB) • ⚪ 0 BAuthentication, profile, and account management bundles
Status: 5 added / 5 removed Editors & Dialogs — 706 B (baseline 706 B) • ⚪ 0 BModals, dialogs, drawers, and in-app editors
Status: 1 added / 1 removed UI Components — 43.2 kB (baseline 43.2 kB) • ⚪ 0 BReusable component library chunks
Status: 5 added / 5 removed Data & Services — 2.47 MB (baseline 2.47 MB) • 🔴 +4.17 kBStores, services, APIs, and repositories
Status: 13 added / 13 removed Utilities & Hooks — 57.6 kB (baseline 57.6 kB) • ⚪ 0 BHelpers, composables, and utility bundles
Status: 13 added / 13 removed Vendor & Third-Party — 8.86 MB (baseline 8.86 MB) • ⚪ 0 BExternal libraries and shared vendor chunks
Other — 7.38 MB (baseline 7.38 MB) • 🔴 +439 BBundles that do not match a named category
Status: 51 added / 51 removed |
…ed by reset
- Replace :class='cn('...')' with static class and remove unused cn import
in ErrorOverlay
- Fix prompt-only cloud validation errors being wiped by resetExecutionState
by capturing the error before reset and applying it after
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (3)
src/components/error/ErrorOverlay.vue (2)
73-73: Inlineref('')creates an anonymous ref; prefer a named constant.
useErrorGroups(ref(''), t)works correctly (therefis stable for the component lifetime), but naming it improves readability and makes the intent explicit.♻️ Proposed refactor
+const searchQuery = ref('') -const { groupedErrorMessages } = useErrorGroups(ref(''), t) +const { groupedErrorMessages } = useErrorGroups(searchQuery, t)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/error/ErrorOverlay.vue` at line 73, Replace the anonymous ref passed into useErrorGroups by creating a named const (e.g., const errorKey = ref('')) and pass that named ref into useErrorGroups instead of ref(''); update any references to the original anonymous ref usage around groupedErrorMessages to use the new constant to improve readability and make the intent explicit when calling useErrorGroups(errorKey, t).
2-6: Missing leave-transition classes causes abrupt dismissal.The
<Transition>only defines enter animation. WhenisVisiblebecomes false (on dismiss), the overlay disappears instantly with no animation, inconsistent with the smooth enter slide-down.✨ Proposed fix – add leave classes
<Transition enter-active-class="transition-all duration-300 ease-out" enter-from-class="-translate-y-3 opacity-0" enter-to-class="translate-y-0 opacity-100" + leave-active-class="transition-all duration-200 ease-in" + leave-from-class="translate-y-0 opacity-100" + leave-to-class="-translate-y-3 opacity-0" >🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/error/ErrorOverlay.vue` around lines 2 - 6, The Transition currently only defines enter classes so the overlay dismisses abruptly; update the <Transition> element (the Transition wrapper around the overlay) to add matching leave classes — e.g., add leave-active-class, leave-from-class, and leave-to-class that mirror the enter animation in reverse (use a short duration and ease-in, with leave-from being translate-y-0 opacity-100 and leave-to being -translate-y-3 opacity-0) so the overlay animates smoothly on dismissal.src/stores/executionStore.ts (1)
467-479:let promptError = null— prefer an immutable assignment via a helper.Per coding guidelines, "avoid mutable state; prefer immutability and assignment at point of declaration."
promptErroris declared asnulland conditionally reassigned across three branches. Extracting a small helper keeps the assignment at declaration:♻️ Proposed refactor
+function buildPromptError( + error: CloudValidationError['error'] +): PromptError | null { + if (error && typeof error === 'object') { + return { + type: error.type ?? 'error', + message: error.message ?? '', + details: error.details ?? '' + } + } + if (typeof error === 'string') { + return { type: 'error', message: error, details: '' } + } + return null +} function handleCloudValidationError(detail: ExecutionErrorWsMessage): boolean { const extracted = tryExtractValidationError(detail.exception_message) if (!extracted) return false const { error, node_errors } = extracted const hasNodeErrors = node_errors && Object.keys(node_errors).length > 0 - let promptError = null - if (!hasNodeErrors) { - if (error && typeof error === 'object') { - promptError = { - type: error.type ?? 'error', - message: error.message ?? '', - details: error.details ?? '' - } - } else if (typeof error === 'string') { - promptError = { type: 'error', message: error, details: '' } - } else { - return false - } - } + const promptError = hasNodeErrors ? null : buildPromptError(error) + if (!hasNodeErrors && !promptError) return false clearInitializationByPromptId(detail.prompt_id) resetExecutionState(detail.prompt_id)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/stores/executionStore.ts` around lines 467 - 479, Replace the mutable promptError variable with an immutable assignment by extracting the branching logic into a small helper (e.g., buildPromptError) and then declare const promptError = !hasNodeErrors ? buildPromptError(error) : null; implement buildPromptError(error) to return the same shapes: if error is object return { type: error.type ?? 'error', message: error.message ?? '', details: error.details ?? '' }, if string return { type: 'error', message: error, details: '' }, and if neither return null so the caller can still handle the early return (preserve the existing return false behavior when buildPromptError returns null); update references to promptError accordingly and keep function/variable names like promptError, hasNodeErrors, and error to locate the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/stores/executionStore.ts`:
- Around line 445-456: handleServiceLevelError currently uses
isEmpty(detail.node_id) which treats numeric node IDs (including 0) as empty and
incorrectly routes OSS runtime errors to service-level handling; change the
guard to an explicit presence check on detail.node_id (e.g., check
detail.node_id !== null && detail.node_id !== undefined && detail.node_id !==
'') so numeric IDs are considered present, keep the rest of the function
(clearInitializationByPromptId, resetExecutionState, setting lastPromptError)
unchanged, and ensure handleExecutionError will continue down the OSS path when
a node_id is present.
- Around line 450-453: The message template for lastPromptError currently
interpolates detail.exception_type without a fallback causing "null: ..." or
"undefined: ..."; update the construction of lastPromptError.message to use the
same null-coalescing used for type (e.g., replace the template that uses
detail.exception_type with one that uses detail.exception_type ?? 'error' or
omit the prefix when absent) so message and type remain consistent; adjust the
assignment around lastPromptError.value and the message construction to
reference detail.exception_type ?? 'error' (or conditional inclusion) and
detail.exception_message, leaving details as-is.
---
Duplicate comments:
In `@src/stores/executionStore.ts`:
- Around line 458-491: The PR correctly preserves prompt-only validation errors
by extracting the error before calling resetExecutionState and then setting
lastPromptError or lastNodeErrors after reset; ensure the ordering in
handleCloudValidationError remains: call tryExtractValidationError, capture
promptError, call clearInitializationByPromptId and resetExecutionState, then
assign lastNodeErrors.value or lastPromptError.value as appropriate (references:
handleCloudValidationError, tryExtractValidationError,
clearInitializationByPromptId, resetExecutionState, lastNodeErrors,
lastPromptError).
---
Nitpick comments:
In `@src/components/error/ErrorOverlay.vue`:
- Line 73: Replace the anonymous ref passed into useErrorGroups by creating a
named const (e.g., const errorKey = ref('')) and pass that named ref into
useErrorGroups instead of ref(''); update any references to the original
anonymous ref usage around groupedErrorMessages to use the new constant to
improve readability and make the intent explicit when calling
useErrorGroups(errorKey, t).
- Around line 2-6: The Transition currently only defines enter classes so the
overlay dismisses abruptly; update the <Transition> element (the Transition
wrapper around the overlay) to add matching leave classes — e.g., add
leave-active-class, leave-from-class, and leave-to-class that mirror the enter
animation in reverse (use a short duration and ease-in, with leave-from being
translate-y-0 opacity-100 and leave-to being -translate-y-3 opacity-0) so the
overlay animates smoothly on dismissal.
In `@src/stores/executionStore.ts`:
- Around line 467-479: Replace the mutable promptError variable with an
immutable assignment by extracting the branching logic into a small helper
(e.g., buildPromptError) and then declare const promptError = !hasNodeErrors ?
buildPromptError(error) : null; implement buildPromptError(error) to return the
same shapes: if error is object return { type: error.type ?? 'error', message:
error.message ?? '', details: error.details ?? '' }, if string return { type:
'error', message: error, details: '' }, and if neither return null so the caller
can still handle the early return (preserve the existing return false behavior
when buildPromptError returns null); update references to promptError
accordingly and keep function/variable names like promptError, hasNodeErrors,
and error to locate the change.
- Replace isEmpty(node_id) with explicit presence check to prevent numeric node IDs from being misclassified as service-level errors - Guard exception_type in message template to avoid 'null: ...' output when exception_type is absent - Remove unused isEmpty import from es-toolkit/compat
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/stores/executionStore.ts`:
- Around line 753-762: The computed allErrorExecutionIds currently pushes
String(lastExecutionError.value.node_id) unguarded which can produce
"null"/"undefined"; update the allErrorExecutionIds computed to only push
lastExecutionError.value.node_id when lastExecutionError.value exists and
lastExecutionError.value.node_id is not null/undefined (e.g. check typeof or !=
null) so you only push valid IDs, and continue to spread
Object.keys(lastNodeErrors.value) from lastNodeErrors as before; reference the
allErrorExecutionIds computed, lastExecutionError, and lastNodeErrors symbols
when making this guard change.
- Around line 317-320: The handler handleExecutionStart resets some error state
but misses clearing node-level errors, causing stale entries to affect
totalErrorCount and allErrorExecutionIds; update handleExecutionStart to set
lastNodeErrors.value = null alongside lastExecutionError.value = null,
lastPromptError.value = null and isErrorOverlayOpen.value = false so node
validation errors are cleared at the start of a new execution.
…ErrorExecutionIds - Add lastNodeErrors.value = null in handleExecutionStart to prevent stale node errors from persisting into the next execution - Guard against null/undefined node_id before pushing to allErrorExecutionIds
- Catch non-JSON server errors and wrap into PromptExecutionError - Differentiate 500 error i18n messages by cloud/local environment - Properly show error details in right side panel Error Cards
- ErrorOverlay: clamp messages to 3 lines and handle word breaks - ErrorNodeCard: clamp message height to 4 lines with scroll, enforce word breaks for traceback - Prevent unspaced long text (e.g. tensors/paths) from breaking flex layouts
- Extract getRootParentNode utility to eliminate duplicated parent node parsing logic in useFocusNode and useErrorGroups - Move expandFocusedErrorGroup watcher from useErrorGroups to TabErrors.vue to fix race condition with ErrorOverlay - Decouple isCloud from error object: unify server_error type in api.ts, resolve i18n keys at display time in useErrorGroups - Extract cloud validation error logic into executionErrorUtil.ts with classifyCloudValidationError for testability (18 unit tests) - Use deterministic JSON boundary extraction (indexOf + lastIndexOf) - Split totalErrorCount into composable per-category computeds (promptErrorCount, nodeErrorCount, executionErrorCount) - Add role='alert' and aria-live='assertive' to ErrorOverlay - Remove unnecessary try/catch from contactSupport in TabErrors.vue
|
The browser tests that check execution error behaviors will need to be updated, otherwise looks good to merge. |
… error dialog - Add data-testid="error-overlay" to ErrorOverlay.vue for stable test selection - Update execution.spec.ts and dialog.spec.ts to use ErrorOverlay selector - Override UseNewMenu to 'Top' in error test blocks (ErrorOverlay requires Top menu) - Replace canvas clickEmptySpace with Escape key to avoid toolbar interception - Use command.executeCommand instead of queueButton.click for Top menu compatibility
|
Updating Playwright Expectations |
Summary
Enhances the error panel with node-specific views: single-node selection shows errors grouped by message in compact mode, container nodes (subgraph/group) expose child errors via a badge and "See Error" button, and a floating ErrorOverlay appears after execution failure with a deduplicated summary and quick navigation to the errors tab.
Changes
TabError.vue; merge all error display intoTabErrors.vueand drop the separateerrortab type fromrightSidePanelStoreclass_type) and rendersErrorNodeCardin compact modeSectionWidgetsisErrorOverlayOpen/showErrorOverlay/dismissErrorOverlayadded toexecutionStoreexecutionStore(allErrorExecutionIds,hasInternalErrorForNode); spliterrorGroupsintoallErrorGroups(unfiltered) andtabErrorGroups(selection-filtered); moveErrorOverlaybusiness logic intouseErrorGroupsReview Focus
useErrorGroups.ts: split intoallErrorGroups/tabErrorGroupsand the newfilterBySelectionparameter flowexecutionStore.ts:hasInternalErrorForNodehelper andallErrorExecutionIdscomputedErrorOverlay.vue: integration withexecutionStoreoverlay state anduseErrorGroupsScreenshots