Comfy-Org / Comfy-Org/ComfyUI

Prompt validation fails on deep acyclic workflows

Open
#14,911 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Python
Stars
133k
Forks
15.7k
Avg merge
1d 7h
Merged PRs (30d)
158

Description

## Custom Node Testing

- [x] Reproduced without any installed custom-node packages. The script below registers two in-memory test node classes only to build a deterministic acyclic graph.

## Expected Behavior

A valid acyclic prompt graph should pass validation without depending on Python's recursion limit.

## Actual Behavior

`validate_inputs()` recursively awaits itself once per linked node. On current `master` at `917faef771a2fd2f14f44af94f17da3d0b2803a3`, the exact cutoff moves slightly with the caller's stack depth, but it is close to 1,000 linked nodes. A 2,000-node linear graph reliably returns an invalid result even though it is acyclic:

```text
result: (False, [], '1999')
validated node: 1020
type: exception_during_inner_validation
message: Exception when validating inner node
details: maximum recursion depth exceeded
exception_type: RecursionError
```

## Steps to Reproduce

Run this from the ComfyUI repository with its normal Python environment:

```python
import asyncio

import execution

class Source:
RETURN_TYPES = ("INT",)

@classmethod
def INPUT_TYPES(cls):
return {"required": {}}

class Link:
RETURN_TYPES = ("INT",)

@classmethod
def INPUT_TYPES(cls):
return {"required": {"value": ("INT", {})}}

execution.nodes.NODE_CLASS_MAPPINGS["ValidationSource"] = Source
execution.nodes.NODE_CLASS_MAPPINGS["ValidationLink"] = Link

size = 2_000
prompt = {"0": {"class_type": "ValidationSource", "inputs": {}}}
for index in range(1, size):
prompt[str(index)] = {
"class_type": "ValidationLink",
"inputs": {"value": [str(index - 1), 0]},
}

validated = {}
result = asyncio.run(
execution.validate_inputs("repro", prompt, str(size - 1), validated)
)
print(result)
print(next(value for value in validated.values() if value[1]))
```

## Debug Logs

```text
RecursionError: maximum recursion depth exceeded
```

The exception is caught by the parent validation frame and stored as `exception_during_inner_validation`, so the root call returns `False` rather than raising.

## Other

I tested an explicit-stack prototype before proposing a PR. It validates 1,000, 2,000, and 10,000-node chains and matched the recursive implementation for awaited validator rewrites, cancellation and exceptions, shared-DAG caching, partial outputs, custom-validator ordering, and 4,096 overlapping-cycle graphs.

There is a real tradeoff to discuss first:

- On a 4,000-node linear chain, with the reference recursion limit raised only for comparison, two paired CPU-time runs measured `72.55 ms -> 10.68 ms` and `73.73 ms -> 10.39 ms` (about 6.8-7.1x).
- On ordinary fan-in and shared-DAG fixtures, the prototype was about 44-46% slower, although the absolute increase was only 0.16-0.22 ms per validation.
- The implementation is materially larger than the current recursive function and would need broader upstream regression coverage before a PR.

A prior [public autoresearch trajectory](https://dashboard.weco.ai/share/mpQ420TdrbtI68sx-BE6MZoiUL-VlEdU) records the explicit-stack direction. I am not treating that prototype as PR-ready. Would maintainers accept an iterative implementation with the measured sub-millisecond ordinary-graph overhead, or should this remain recursive unless a simpler approach avoids that regression?

The source-pinned evaluator, repeated measurements, and current NO-GO report are available in [`dexhunter/osspr-automation`](https://github.com/dexhunter/osspr-automation/tree/e84b0a800c78ff52a8a414066b9718c28d2e8208/remote_metric_scripts/Comfy-Org__ComfyUI__deep_prompt_validation). The tightened evaluator rejects the current prototype on the ordinary fan-in guard.

Contributor guide

Open the contributing guide

Research direction

Start at execution.validate_inputs and run the supplied 2,000-node reproduction in ComfyUI's normal Python environment. Compare a proposed validation approach against the documented deep-chain, shared-DAG, cancellation, exception, partial-output, custom-validator, and cycle cases; done means valid deep acyclic graphs pass without recursion failure while existing behavior is preserved.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
backend
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.