Skip to content

fix(dynamicprompts): prevent hang on unknown wildcards#9307

Open
Pfannkuchensack wants to merge 4 commits into
invoke-ai:mainfrom
Pfannkuchensack:fix/dynamicprompts-unknown-wildcard-hang
Open

fix(dynamicprompts): prevent hang on unknown wildcards#9307
Pfannkuchensack wants to merge 4 commits into
invoke-ai:mainfrom
Pfannkuchensack:fix/dynamicprompts-unknown-wildcard-hang

Conversation

@Pfannkuchensack

@Pfannkuchensack Pfannkuchensack commented Jun 26, 2026

Copy link
Copy Markdown
Collaborator

Summary

Referencing an unknown wildcard previously hung the combinatorial generator forever: its not-found fallback yields the wrapped wildcard infinitely, and the variant dedup logic discards those duplicates without ever advancing. This froze the UI prompt preview. Unknown wildcards are now detected up front and reported as a clear error instead of attempting generation.

This is the minimal fix extracted from #9290 — it contains only the hang fix, none of the wildcard-file feature (no wildcards_dir setting, no WildcardManager file loading).

Related Issues / Discussions

Replaces #9290

QA Instructions

  1. Open the canvas/generation tab and enter a prompt containing an unknown wildcard, e.g. {__random__a|b|c}.
  2. Before this change the dynamic prompts preview spinner would hang indefinitely (the request never returned).
  3. After this change the preview returns immediately and shows the error: No values found for wildcard(s): random.

The same guard applies to the DynamicPrompt node, which now raises a clear ValueError instead of hanging the invocation.

Automated tests:

pytest tests/app/util/test_dynamicprompts.py tests/app/routers/test_utilities.py

Merge Plan

Standard merge — no special handling required. Changes are additive and backwards-compatible:

No new config settings.
No DB schema or redux slice changes.
No generated docs/settings changes.

Checklist

  • The PR has a short but descriptive title, suitable for a changelog
  • Tests added / updated (if applicable)
  • ❗Changes to a redux slice have a corresponding migration
  • Documentation added / updated (if applicable)
  • Updated What's New copy (if doing a release after this PR)

Referencing an unknown wildcard previously hung the combinatorial generator
forever: its not-found fallback yields the wrapped wildcard infinitely, and
the variant dedup logic discards those duplicates without ever advancing.
This froze the UI prompt preview. Unknown wildcards are now detected up front
and reported as a clear error instead of attempting generation.
@github-actions github-actions Bot added api python PRs that change python files invocations PRs that change invocations python-tests PRs that change python tests labels Jun 26, 2026

@lstein lstein left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fix adds find_missing_wildcards() and short-circuits with an error before running the generators. The detection logic itself is sound (correct dynamicprompts API usage, and InvokeAI always uses an empty WildcardManager so treating every referenced wildcard as unresolvable is internally consistent). However, after running the generators in this venv (dynamicprompts 0.31.0), the guard is much broader than the actual failure condition, which introduces two regressions.

1. (High) The guard errors on prompts that never hang — the hang is specific to unknown wildcards used as variant values

find_missing_wildcards() flags any unknown wildcard, but only a wildcard nested inside a variant actually loops. Verified against CombinatorialPromptGenerator:

Prompt Combinatorial result
a __nope__ b ['a __nope__ b', ...] (works)
__nope__ ['__nope__', ...] (works)
{__nope__|x} ❌ HANG
{__random__8chan|...} ❌ HANG (the reported case)

So a __nope__ b previously generated valid output, but now find_missing_wildcards("a __nope__ b") == ["nope"], so the router attaches an error and the invocation raises ValueError. Any prompt containing literal double-underscore text that isn't inside a variant (e.g. trigger-token style a photo, __my_style__) is now broken though it worked before.

Suggested fix: narrow detection to wildcards reachable as variant values (only flag a wildcard whose ancestor is a VariantCommand), rather than every wildcard in the tree.

2. (Medium) The guard fires regardless of combinatorial, but the random generator never hangs

utilities.py:60 and prompt.py:36 run the check unconditionally. The random generator handles unknown wildcards gracefully — verified: RandomPromptGenerator().generate("{__random__8chan|fenster|stuff}", ...) returns ['fenster', '__random__8chan', 'stuff'], no hang. So for combinatorial=False the guard is pure regression: it turns working output into an error.

This matters most in DynamicPromptInvocation, where combinatorial defaults to False (prompt.py:31) — the default code path now errors on prompts it used to handle.

Suggested fix: gate the check on if combinatorial: / if self.combinatorial:.

Things that are fine

  • parse()'s ParseException is swallowed and [] returned; the generators re-raise it and the router's existing except ParseException still handles malformed prompts. Consistent.
  • Variable-assignment wildcards (${v=__nope__}${v}) are not traversed by _iter_wildcard_names, but they don't hang the combinatorial generator either, so that traversal gap is not a correctness hole.
  • New tests are correct and match current behavior.

Root cause / recommendation

Both findings stem from one root cause: the guard is broader than the bug. Narrowing detection to variant-nested wildcards and gating on combinatorial would fix the hang without regressing the several classes of previously-working prompts (including the invocation's default mode). Tests should be extended to cover a __nope__ b (combinatorial → no error) and the random-generator path.

…ariant values

Only an unknown wildcard used as a variant value hangs the combinatorial
generator; a bare `a __nope__ b` and the random generator both handle unknown
wildcards fine. Restrict detection to variant-nested wildcards and gate the
check on the combinatorial path so previously-working prompts no longer error.
@lstein lstein self-assigned this Jun 28, 2026
@Pfannkuchensack Pfannkuchensack requested a review from lstein June 28, 2026 14:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

6.13.5 Library Updates api bug Something isn't working invocations PRs that change invocations python PRs that change python files python-tests PRs that change python tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants