From 36d59f26cd3d4d0615d60d44ba62865e70ef20ec Mon Sep 17 00:00:00 2001 From: Christian Byrne Date: Sat, 14 Feb 2026 07:16:14 -0800 Subject: [PATCH] fix: SaveImage node not updating outputs during batch runs (vue-nodes) (#8862) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Fix vue-node outputs not updating during batch runs by creating a new object reference on merge. ## Changes - **What**: Spread merged output object in `setOutputsByLocatorId` so Vue detects the assignment as a change. Adds regression test asserting reference identity changes on merge. ## Review Focus One-line fix at `imagePreviewStore.ts:155`: `{ ...existingOutput }` instead of `existingOutput`. This matches the spread pattern already used in `restoreOutputs` (line 368). The root cause: Vue skips reactivity triggers for same-reference assignments. The merge path mutated `existingOutput` in-place then reassigned the same object, so `nodeMedia` computed in `LGraphNode.vue` never re-evaluated. > Notion: https://www.notion.so/comfy-org/3066d73d36508165873fcbb9673dece7 ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-8862-fix-SaveImage-node-not-updating-outputs-during-batch-runs-vue-nodes-3076d73d36508133b1faeae66dcccf01) by [Unito](https://www.unito.io) Co-authored-by: Terry Jia --- src/stores/imagePreviewStore.test.ts | 18 ++++++++++++++++++ src/stores/imagePreviewStore.ts | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/stores/imagePreviewStore.test.ts b/src/stores/imagePreviewStore.test.ts index c4d0e08711..7defd072c5 100644 --- a/src/stores/imagePreviewStore.test.ts +++ b/src/stores/imagePreviewStore.test.ts @@ -85,6 +85,24 @@ describe('imagePreviewStore setNodeOutputsByExecutionId with merge', () => { ) expect(store.nodeOutputs[executionId]?.images).toHaveLength(2) }) + + it('should create a new object reference on merge so Vue detects the change', () => { + const store = useNodeOutputStore() + const executionId = '1' + + const initialOutput = createMockOutputs([{ filename: 'a.png' }]) + store.setNodeOutputsByExecutionId(executionId, initialOutput) + + const refBefore = store.nodeOutputs[executionId] + + const newOutput = createMockOutputs([{ filename: 'b.png' }]) + store.setNodeOutputsByExecutionId(executionId, newOutput, { merge: true }) + + const refAfter = store.nodeOutputs[executionId] + + expect(refAfter).not.toBe(refBefore) + expect(refAfter?.images).toHaveLength(2) + }) }) describe('imagePreviewStore restoreOutputs', () => { diff --git a/src/stores/imagePreviewStore.ts b/src/stores/imagePreviewStore.ts index 93c7c8e793..6919d8ecd0 100644 --- a/src/stores/imagePreviewStore.ts +++ b/src/stores/imagePreviewStore.ts @@ -152,7 +152,7 @@ export const useNodeOutputStore = defineStore('nodeOutput', () => { existingOutput[k] = newValue } } - nodeOutputs.value[nodeLocatorId] = existingOutput + nodeOutputs.value[nodeLocatorId] = { ...existingOutput } return } }