Skip to content

Commit 1749cfa

Browse files
arjansinghDrJKL
andauthored
[fix] properly show error states (#5758)
## Summary I want to take a more general look at `comfyApp.graph.onTrigger` but this is the cleanest fix I could come up with for #5694. I will explore simplifying onTrigger in a separate PR. ## Changes 1. Create a `node:slot-errors:changed` trigger. 2. Trigger it if we find any of the node slots have errors. 3. Check each node to see if there is any error present. 4. Add an error class if there are. ## Screenshots (if applicable) Working error states! <img width="1049" height="987" alt="Screenshot 2025-09-23 at 8 40 04 PM" src="https://github.com/user-attachments/assets/30e13283-129c-4d9c-b342-e7037582998a" /> ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-5758-fix-properly-show-error-states-2786d73d365081cbbf62c314c7f5f380) by [Unito](https://www.unito.io) --------- Co-authored-by: Alexander Brown <[email protected]>
1 parent 0fea54c commit 1749cfa

File tree

3 files changed

+60
-12
lines changed

3 files changed

+60
-12
lines changed

src/components/graph/GraphCanvas.vue

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -307,13 +307,23 @@ watch(
307307
removeSlotError(node)
308308
const nodeErrors = lastNodeErrors?.[node.id]
309309
if (!nodeErrors) continue
310+
311+
let slotErrorsChanged = false
310312
for (const error of nodeErrors.errors) {
311-
if (error.extra_info && error.extra_info.input_name) {
312-
const inputIndex = node.findInputSlot(error.extra_info.input_name)
313-
if (inputIndex !== -1) {
314-
node.inputs[inputIndex].hasErrors = true
315-
}
316-
}
313+
if (!error.extra_info?.input_name) continue
314+
315+
const inputIndex = node.findInputSlot(error.extra_info.input_name)
316+
if (inputIndex === -1) continue
317+
318+
node.inputs[inputIndex].hasErrors = true
319+
slotErrorsChanged = true
320+
}
321+
322+
// Trigger Vue node data update if slot errors changed
323+
if (slotErrorsChanged && comfyApp.graph.onTrigger) {
324+
comfyApp.graph.onTrigger('node:slot-errors:changed', {
325+
nodeId: node.id
326+
})
317327
}
318328
}
319329

src/composables/graph/useGraphNodeManager.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,28 @@ export function useGraphNodeManager(graph: LGraph): GraphNodeManager {
435435
})
436436
}
437437
}
438+
} else if (
439+
action === 'node:slot-errors:changed' &&
440+
param &&
441+
typeof param === 'object'
442+
) {
443+
const event = param as { nodeId: string | number }
444+
const nodeId = String(event.nodeId)
445+
const litegraphNode = nodeRefs.get(nodeId)
446+
const currentData = vueNodeData.get(nodeId)
447+
448+
if (litegraphNode && currentData) {
449+
// Re-extract slot data with updated hasErrors properties
450+
vueNodeData.set(nodeId, {
451+
...currentData,
452+
inputs: litegraphNode.inputs
453+
? [...litegraphNode.inputs]
454+
: undefined,
455+
outputs: litegraphNode.outputs
456+
? [...litegraphNode.outputs]
457+
: undefined
458+
})
459+
}
438460
}
439461

440462
// Call original trigger handler if it exists

src/renderer/extensions/vueNodes/components/LGraphNode.vue

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,11 @@ import { computed, inject, onErrorCaptured, onMounted, provide, ref } from 'vue'
136136
137137
import type { VueNodeData } from '@/composables/graph/useGraphNodeManager'
138138
import { useErrorHandling } from '@/composables/useErrorHandling'
139-
import { LiteGraph } from '@/lib/litegraph/src/litegraph'
139+
import {
140+
type INodeInputSlot,
141+
type INodeOutputSlot,
142+
LiteGraph
143+
} from '@/lib/litegraph/src/litegraph'
140144
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
141145
import { useCanvasInteractions } from '@/renderer/core/canvas/useCanvasInteractions'
142146
import { TransformStateKey } from '@/renderer/core/layout/injectionKeys'
@@ -200,9 +204,21 @@ const hasExecutionError = computed(
200204
)
201205
202206
// Computed error states for styling
203-
const hasAnyError = computed(
204-
(): boolean => !!(hasExecutionError.value || nodeData.hasErrors || error)
205-
)
207+
const hasAnyError = computed((): boolean => {
208+
return (
209+
!!hasExecutionError.value ||
210+
!!nodeData.hasErrors ||
211+
!!error ||
212+
// Type assertions needed because VueNodeData.inputs/outputs are typed as unknown[]
213+
// but at runtime they contain INodeInputSlot/INodeOutputSlot objects
214+
!!nodeData.inputs?.some(
215+
(slot) => (slot as INodeInputSlot)?.hasErrors ?? false
216+
) ||
217+
!!nodeData.outputs?.some(
218+
(slot) => (slot as INodeOutputSlot)?.hasErrors ?? false
219+
)
220+
)
221+
})
206222
207223
const bypassed = computed((): boolean => nodeData.mode === 4)
208224
@@ -263,7 +279,7 @@ const { latestPreviewUrl, shouldShowPreviewImg } = useNodePreviewState(
263279
264280
const borderClass = computed(() => {
265281
if (hasAnyError.value) {
266-
return 'border-error'
282+
return 'border-red-500 dark-theme:border-red-500'
267283
}
268284
if (executing.value) {
269285
return 'border-blue-500'
@@ -276,7 +292,7 @@ const outlineClass = computed(() => {
276292
return undefined
277293
}
278294
if (hasAnyError.value) {
279-
return 'outline-error'
295+
return 'outline-red-500'
280296
}
281297
if (executing.value) {
282298
return 'outline-blue-500'

0 commit comments

Comments
 (0)