mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-01 03:31:58 +00:00
[enhance] Add rich context to RecursionError messages (#1160)
This commit is contained in:
@@ -131,7 +131,14 @@ export class ExecutableNodeDTO implements ExecutableLGraphNode {
|
|||||||
*/
|
*/
|
||||||
resolveInput(slot: number, visited = new Set<string>()): ResolvedInput | undefined {
|
resolveInput(slot: number, visited = new Set<string>()): ResolvedInput | undefined {
|
||||||
const uniqueId = `${this.subgraphNode?.subgraph.id}:${this.node.id}[I]${slot}`
|
const uniqueId = `${this.subgraphNode?.subgraph.id}:${this.node.id}[I]${slot}`
|
||||||
if (visited.has(uniqueId)) throw new RecursionError(`While resolving subgraph input [${uniqueId}]`)
|
if (visited.has(uniqueId)) {
|
||||||
|
const nodeInfo = `${this.node.id}${this.node.title ? ` (${this.node.title})` : ""}`
|
||||||
|
const pathInfo = this.subgraphNodePath.length > 0 ? ` at path ${this.subgraphNodePath.join(":")}` : ""
|
||||||
|
throw new RecursionError(
|
||||||
|
`Circular reference detected while resolving input ${slot} of node ${nodeInfo}${pathInfo}. ` +
|
||||||
|
`This creates an infinite loop in link resolution. UniqueID: [${uniqueId}]`,
|
||||||
|
)
|
||||||
|
}
|
||||||
visited.add(uniqueId)
|
visited.add(uniqueId)
|
||||||
|
|
||||||
const input = this.inputs.at(slot)
|
const input = this.inputs.at(slot)
|
||||||
@@ -195,7 +202,14 @@ export class ExecutableNodeDTO implements ExecutableLGraphNode {
|
|||||||
*/
|
*/
|
||||||
resolveOutput(slot: number, type: ISlotType, visited: Set<string>): ResolvedInput | undefined {
|
resolveOutput(slot: number, type: ISlotType, visited: Set<string>): ResolvedInput | undefined {
|
||||||
const uniqueId = `${this.subgraphNode?.subgraph.id}:${this.node.id}[O]${slot}`
|
const uniqueId = `${this.subgraphNode?.subgraph.id}:${this.node.id}[O]${slot}`
|
||||||
if (visited.has(uniqueId)) throw new RecursionError(`While resolving subgraph output [${uniqueId}]`)
|
if (visited.has(uniqueId)) {
|
||||||
|
const nodeInfo = `${this.node.id}${this.node.title ? ` (${this.node.title})` : ""}`
|
||||||
|
const pathInfo = this.subgraphNodePath.length > 0 ? ` at path ${this.subgraphNodePath.join(":")}` : ""
|
||||||
|
throw new RecursionError(
|
||||||
|
`Circular reference detected while resolving output ${slot} of node ${nodeInfo}${pathInfo}. ` +
|
||||||
|
`This creates an infinite loop in link resolution. UniqueID: [${uniqueId}]`,
|
||||||
|
)
|
||||||
|
}
|
||||||
visited.add(uniqueId)
|
visited.add(uniqueId)
|
||||||
|
|
||||||
// Upstreamed: Bypass nodes are bypassed using the first input with matching type
|
// Upstreamed: Bypass nodes are bypassed using the first input with matching type
|
||||||
|
|||||||
@@ -293,7 +293,15 @@ export class SubgraphNode extends LGraphNode implements BaseLGraph {
|
|||||||
/** Internal recursion param. The set of visited nodes. */
|
/** Internal recursion param. The set of visited nodes. */
|
||||||
visited = new Set<SubgraphNode>(),
|
visited = new Set<SubgraphNode>(),
|
||||||
): ExecutableLGraphNode[] {
|
): ExecutableLGraphNode[] {
|
||||||
if (visited.has(this)) throw new RecursionError("while flattening subgraph")
|
if (visited.has(this)) {
|
||||||
|
const nodeInfo = `${this.id}${this.title ? ` (${this.title})` : ""}`
|
||||||
|
const subgraphInfo = `'${this.subgraph.name || "Unnamed Subgraph"}'`
|
||||||
|
const depth = subgraphNodePath.length
|
||||||
|
throw new RecursionError(
|
||||||
|
`Circular reference detected at depth ${depth} in node ${nodeInfo} of subgraph ${subgraphInfo}. ` +
|
||||||
|
`This creates an infinite loop in the subgraph hierarchy.`,
|
||||||
|
)
|
||||||
|
}
|
||||||
visited.add(this)
|
visited.add(this)
|
||||||
|
|
||||||
const subgraphInstanceIdPath = [...subgraphNodePath, this.id]
|
const subgraphInstanceIdPath = [...subgraphNodePath, this.id]
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
import { describe, expect, it, vi } from "vitest"
|
import { describe, expect, it, vi } from "vitest"
|
||||||
|
|
||||||
import { LGraph } from "@/litegraph"
|
import { LGraph } from "@/litegraph"
|
||||||
import { SubgraphNode } from "@/subgraph/SubgraphNode"
|
|
||||||
|
|
||||||
import { subgraphTest } from "./fixtures/subgraphFixtures"
|
import { subgraphTest } from "./fixtures/subgraphFixtures"
|
||||||
import {
|
import {
|
||||||
createEventCapture,
|
|
||||||
createTestSubgraph,
|
createTestSubgraph,
|
||||||
createTestSubgraphNode,
|
createTestSubgraphNode,
|
||||||
} from "./fixtures/subgraphHelpers"
|
} from "./fixtures/subgraphHelpers"
|
||||||
@@ -427,4 +425,4 @@ describe("SubgraphMemory - Performance and Scale", () => {
|
|||||||
expect(rootGraph.nodes.length).toBe(0)
|
expect(rootGraph.nodes.length).toBe(0)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -347,7 +347,7 @@ describe("SubgraphNode Execution", () => {
|
|||||||
const executableNodes = new Map()
|
const executableNodes = new Map()
|
||||||
expect(() => {
|
expect(() => {
|
||||||
subgraphNode.getInnerNodes(executableNodes)
|
subgraphNode.getInnerNodes(executableNodes)
|
||||||
}).toThrow(/while flattening subgraph/i)
|
}).toThrow(/Circular reference detected.*infinite loop in the subgraph hierarchy/i)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should handle nested subgraph execution", () => {
|
it("should handle nested subgraph execution", () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user