{"record":{"id":"838f5d2ed9b70fb1","repo":"invoke-ai/InvokeAI","slug":"call-saved-workflow-generator-backed-batch-child-w","errorCode":null,"errorMessage":"call_saved_workflow generator-backed batch child workflow is missing generator node '{generator_source_id}'","messagePattern":"call_saved_workflow generator-backed batch child workflow is missing generator node '(.+?)'","errorType":"exception","errorClass":"UnsupportedWorkflowNodeError","httpStatus":null,"severity":"error","filePath":"invokeai/app/services/session_processor/workflow_call_batch.py","lineNumber":584,"sourceCode":"    for node in workflow_nodes.values():\n        if not _is_invocation_node(node):\n            continue\n        node_data = node[\"data\"]\n        node_id = node_data.get(\"id\")\n        node_type = node_data.get(\"type\")\n        if not isinstance(node_id, str) or not isinstance(node_type, str):\n            continue\n        if node_type.endswith(\"_generator\"):\n            continue\n        if node_type not in SUPPORTED_BATCH_TYPES:\n            continue\n\n        field_name = BATCH_FIELD_NAMES[node_type]\n        generator_source_id = _resolve_batch_items_from_inputs(node_id, field_name, workflow_edges, workflow_nodes)\n        if generator_source_id is not None:\n            generator_node = workflow_nodes.get(generator_source_id)\n            if generator_node is None:\n                raise UnsupportedWorkflowNodeError(\n                    f\"call_saved_workflow generator-backed batch child workflow is missing generator node '{generator_source_id}'\"\n                )\n            generator_node_type = generator_node[\"data\"].get(\"type\") if _is_invocation_node(generator_node) else None\n            if generator_node_type == \"image_generator\" and services is None and resolve_generator_items:\n                raise UnsupportedWorkflowNodeError(\n                    \"call_saved_workflow image-generator-backed batch child workflows require runtime services\"\n                )\n            batch_items = (\n                _resolve_generator_items(generator_node, services, user_id, maximum_children)\n                if resolve_generator_items\n                else _get_generator_placeholder_items(generator_node)\n            )\n            used_generator_node_ids.add(generator_source_id)\n            if not batch_items:\n                raise UnsupportedWorkflowNodeError(\n                    f\"call_saved_workflow generator-backed batch child workflow node '{generator_source_id}' produced no batch items\"\n                )\n        else:","sourceCodeStart":566,"sourceCodeEnd":602,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/app/services/session_processor/workflow_call_batch.py#L566-L602","documentation":"When a batch field resolves to a generator source id, build_batch_child_workflow_session_results looks the generator node up in workflow_nodes. If the id has no matching node (dangling edge), it raises this error naming the missing generator node id.","triggerScenarios":"A workflow's edges reference a source node id that no longer exists in nodes (node deleted, JSON edited, or partially imported workflow), for a generator-backed batch child workflow.","commonSituations":"Deleting a generator node in the editor while its edge remained; merging workflow JSON files by hand; API clients submitting workflows with inconsistent nodes/edges arrays.","solutions":["Remove the stale edge pointing at the missing generator node, or reconnect the batch input to an existing generator","Re-add the deleted generator node with the original id","Re-export the workflow from the InvokeAI UI to repair nodes/edges consistency"],"exampleFix":"// before: edge references deleted node\n{\"nodes\": [\"batch-1\", ...], \"edges\": [{\"target\": \"batch-1\", \"source\": \"gen-gone\", \"type\": \"default\"}]}\n// after: remove edge or restore node gen-gone\n{\"nodes\": [\"batch-1\", \"gen-1\", ...], \"edges\": [{\"target\": \"batch-1\", \"source\": \"gen-1\", \"type\": \"default\"}]}","handlingStrategy":"validation","validationCode":"node_ids = {n[\"id\"] for n in workflow.get(\"nodes\", []) if isinstance(n, dict)}\nfor e in workflow.get(\"edges\", []):\n    if e.get(\"source\") not in node_ids or e.get(\"target\") not in node_ids:\n        raise ValueError(f\"dangling edge: {e.get('source')} -> {e.get('target')}\")","typeGuard":"def edges_resolve_to_nodes(workflow: dict) -> bool:\n    ids = {n[\"id\"] for n in workflow.get(\"nodes\", []) if isinstance(n, dict) and \"id\" in n}\n    return all(e.get(\"source\") in ids and e.get(\"target\") in ids for e in workflow.get(\"edges\", []))","tryCatchPattern":"try:\n    build_batch_child_workflow_session_results(...)\nexcept UnsupportedWorkflowNodeError as e:\n    if \"missing generator node\" in str(e):\n        drop_or_reconnect_dangling_edges(extract_missing_id(str(e)))","preventionTips":["Delete edges together with their source nodes when editing workflows","Run an edge/node referential-integrity check before queueing","Never merge workflow JSON files by hand; use the editor export"],"tags":["workflow","dangling-edge","batch"],"backgroundTag":"dangling-edge-reference","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}