Movie Editor: fix forceInput-STRING blocking generation; surface exact blocker; move core panel up

- Regression fix: making forceInput STRING sockets count as connection inputs made
  auto-wire treat them as required inputs needing a STRING source — with none, the
  builder blocked with 'no source available' while the Requirements panel (model/clip/
  vae/latent/image only) stayed green. forceInput widget sockets always have a widget
  fallback, so connection_inputs now marks them required=False: still wireable, never
  blocking. Resolves 'A required pipeline input has no source' with everything green.
- Generation errors now pass through the builder's 'Generation blocked — <node>.<input>
  (<TYPE>): …' detail instead of a vague generic message, so the exact culprit shows.
- Built-in pipeline panel moved directly under Pipeline requirements so it's findable.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
digital-garbage
2026-06-07 13:08:00 +03:00
co-authored by Claude Opus 4.8
parent 023f42eb8a
commit 8ce68e7d74
3 changed files with 12 additions and 6 deletions
+8 -4
View File
@@ -116,10 +116,14 @@ def connection_inputs(node_def: dict) -> list[dict]:
if not isinstance(t, str):
continue
opts = spec[1] if len(spec) > 1 and isinstance(spec[1], dict) else {}
# A widget-typed input is a SOCKET (wireable) only when forceInput is set —
# e.g. refinement_key_input is ("STRING", {"forceInput": True}). Plain widgets
# are handled by widget_inputs, not here.
if t in _WIDGET_TYPES and not opts.get("forceInput"):
if t in _WIDGET_TYPES:
# A widget-typed input is a SOCKET (wireable) only when forceInput is set —
# e.g. refinement_key_input is ("STRING", {"forceInput": True}). It always
# has a widget fallback, so it's NEVER auto-required (it must not block
# generation when left unwired). Plain widgets are handled by widget_inputs.
if not opts.get("forceInput"):
continue
out.append({"name": name, "type": _normalize_type(t), "required": False})
continue
# V3 nodes can mark a required-group input as optional via the flag.
is_required = group == "required" and not opts.get("optional", False)
+1 -1
View File
@@ -735,9 +735,9 @@
function body() {
const b = el("div", "models-body");
b.append(requirementsPanel());
b.append(coreSection());
b.append(composer());
b.append(linksSection());
b.append(coreSection());
const v = validation();
const list = el("div", "slot-list");
if (!config.slots.length) list.append(el("div", "empty-stage", "No models configured yet — use the form above to add loaders."));
+3 -1
View File
@@ -294,12 +294,14 @@
[/\.vae.*no source/i, "Missing Video VAE — add a Video VAE loader in Models."],
[/\.model.*no source/i, "Missing diffusion model — add a Unet loader in Models."],
[/\.clip.*no source/i, "Missing text encoder — add a CLIP loader in Models."],
[/no source available/i, "A required pipeline input has no source — open Models and check the Pipeline requirements checklist."],
[/not installed/i, "A configured node class is not installed in ComfyUI — check Models for details."],
[/Node registry unavailable/i, "ComfyUI is offline or still starting up — wait a moment and try again."],
];
function _friendlyGenError(raw) {
// "Generation blocked — …" already names the exact input(s); pass it through so the
// message is actionable instead of a vague "a required input has no source".
if (/Generation blocked/i.test(raw)) return raw;
for (const [pat, msg] of GEN_ERROR_MAP) if (pat.test(raw)) return msg;
return raw;
}