mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-03-06 13:40:25 +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 {
|
||||
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)
|
||||
|
||||
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 {
|
||||
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)
|
||||
|
||||
// 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. */
|
||||
visited = new Set<SubgraphNode>(),
|
||||
): 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)
|
||||
|
||||
const subgraphInstanceIdPath = [...subgraphNodePath, this.id]
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import { describe, expect, it, vi } from "vitest"
|
||||
|
||||
import { LGraph } from "@/litegraph"
|
||||
import { SubgraphNode } from "@/subgraph/SubgraphNode"
|
||||
|
||||
import { subgraphTest } from "./fixtures/subgraphFixtures"
|
||||
import {
|
||||
createEventCapture,
|
||||
createTestSubgraph,
|
||||
createTestSubgraphNode,
|
||||
} from "./fixtures/subgraphHelpers"
|
||||
@@ -427,4 +425,4 @@ describe("SubgraphMemory - Performance and Scale", () => {
|
||||
expect(rootGraph.nodes.length).toBe(0)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -347,7 +347,7 @@ describe("SubgraphNode Execution", () => {
|
||||
const executableNodes = new Map()
|
||||
expect(() => {
|
||||
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", () => {
|
||||
|
||||
Reference in New Issue
Block a user