[backport core/1.41] fix: prevent nested SubgraphNode input slots from doubling on reload (#10278)

Backport of #10187 to `core/1.41`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10278-backport-core-1-41-fix-prevent-nested-SubgraphNode-input-slots-from-doubling-on-reloa-3276d73d365081449d90e65dd99a5506)
by [Unito](https://www.unito.io)

Co-authored-by: jaeone94 <89377375+jaeone94@users.noreply.github.com>
This commit is contained in:
Comfy Org PR Bot
2026-03-19 09:23:37 +09:00
committed by GitHub
parent c6e0965f5c
commit f80bbe20a1
2 changed files with 55 additions and 1 deletions

View File

@@ -698,6 +698,55 @@ describe('SubgraphNode duplicate input pruning (#9977)', () => {
})
})
describe('Nested SubgraphNode duplicate input prevention', () => {
it('should not duplicate inputs when the referenced subgraph is reconfigured', () => {
setActivePinia(createTestingPinia({ stubActions: false }))
const subgraph = createTestSubgraph({
inputs: [
{ name: 'a', type: 'STRING' },
{ name: 'b', type: 'NUMBER' }
]
})
const node = createTestSubgraphNode(subgraph)
expect(node.inputs).toHaveLength(2)
// Simulate what happens during nested subgraph configure:
// B.configure() calls _configureSubgraph(), which recreates SubgraphInput
// objects and dispatches 'input-added' events with new references.
const serialized = subgraph.asSerialisable()
subgraph.configure(serialized)
// The SubgraphNode's event listener should recognize existing inputs
// by ID and NOT add duplicates.
expect(node.inputs).toHaveLength(2)
expect(node.inputs.every((i) => i._subgraphSlot)).toBe(true)
})
it('should not accumulate inputs across multiple reconfigure cycles', () => {
setActivePinia(createTestingPinia({ stubActions: false }))
const subgraph = createTestSubgraph({
inputs: [
{ name: 'x', type: 'IMAGE' },
{ name: 'y', type: 'VAE' }
]
})
const node = createTestSubgraphNode(subgraph)
expect(node.inputs).toHaveLength(2)
for (let i = 0; i < 5; i++) {
const serialized = subgraph.asSerialisable()
subgraph.configure(serialized)
}
expect(node.inputs).toHaveLength(2)
expect(node.inputs.map((i) => i.name)).toEqual(['x', 'y'])
})
})
describe('SubgraphNode promotion view keys', () => {
it('distinguishes tuples that differ only by colon placement', () => {
setActivePinia(createTestingPinia({ stubActions: false }))

View File

@@ -616,9 +616,14 @@ export class SubgraphNode extends LGraphNode implements BaseLGraph {
const subgraphInput = e.detail.input
const { name, type } = subgraphInput
const existingInput = this.inputs.find(
(input) => input._subgraphSlot === subgraphInput
(input) =>
input._subgraphSlot === subgraphInput ||
(input._subgraphSlot && input._subgraphSlot.id === subgraphInput.id)
)
if (existingInput) {
// Rebind to the new SubgraphInput object and re-register listeners
// (configure recreates SubgraphInput objects with the same id)
this._addSubgraphInputListeners(subgraphInput, existingInput)
const linkId = subgraphInput.linkIds[0]
if (linkId === undefined) return