invoke-ai/InvokeAI · error · InvalidWorkflowInputError

call_saved_workflow input '{input_name}' targets invalid chi

Error message

call_saved_workflow input '{input_name}' targets invalid child workflow inputs on '{node_id}'

What it means

The matched node's 'inputs' member is not a mapping (dict), so the builder cannot insert the dynamic input value. The saved workflow's node data is malformed even though the node type and field validated.

Source

Thrown at invokeai/app/services/shared/workflow_graph_builder.py:158

        )
        if matching_node is None:
            raise InvalidWorkflowInputError(
                f"call_saved_workflow input '{input_name}' targets missing child workflow node '{node_id}'"
            )
        matching_node_data = matching_node["data"]
        node_type = matching_node_data.get("type")
        if not isinstance(node_type, str):
            raise InvalidWorkflowInputError(
                f"call_saved_workflow input '{input_name}' targets missing child workflow node '{node_id}'"
            )
        invocation_class = InvocationRegistry.get_invocation_for_type(node_type)
        if invocation_class is None or field_name not in invocation_class.model_fields:
            raise InvalidWorkflowInputError(
                f"call_saved_workflow input '{input_name}' targets missing child workflow field '{field_name}'"
            )
        inputs = matching_node_data.setdefault("inputs", {})
        if not _is_mapping(inputs):
            raise InvalidWorkflowInputError(
                f"call_saved_workflow input '{input_name}' targets invalid child workflow inputs on '{node_id}'"
            )
        inputs[field_name] = {"value": value}


def apply_workflow_inputs_to_graph(
    graph: Graph, workflow: Mapping[str, Any], workflow_inputs: Mapping[str, Any]
) -> None:
    if not workflow_inputs:
        return

    mutable_workflow = dict(workflow)
    apply_workflow_inputs_to_workflow(mutable_workflow, workflow_inputs)
    for input_name, value in workflow_inputs.items():
        node_id, field_name = parse_call_saved_workflow_dynamic_input(input_name)
        node = graph.nodes.get(node_id)
        if node is None:
            continue

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Fix the node's 'inputs' to be a dict keyed by field name (re-export from the editor).
  2. Re-save the workflow via the UI so the SDK serializes inputs correctly.
  3. Validate the workflow document (inputs mapping per node) before calling apply_workflow_inputs_to_workflow.

Example fix

// before
"inputs": ["prompt"]
// after
"inputs": {"prompt": {"value": "a cat"}}
Defensive patterns

Strategy: type-guard

Validate before calling

def node_inputs_are_mapping(workflow: dict, node_id: str) -> bool:
    node = next((n for n in workflow.get("nodes", []) if isinstance(n, dict) and n.get("id") == node_id), None)
    return isinstance(node, dict) and isinstance(node.get("data", {}).get("inputs"), dict)

Type guard

def has_mapping_inputs(node: dict) -> bool:
    data = node.get("data") if isinstance(node, dict) else None
    return isinstance(data, dict) and isinstance(data.get("inputs"), dict)

Try / catch

try:
    apply_workflow_inputs_to_workflow(workflow, workflow_inputs)
except InvalidWorkflowInputError as e:
    if "invalid child workflow inputs" in str(e):
        log.error("node inputs malformed in saved workflow: %s", e)
        raise ValueError("Fix or re-export the workflow; node inputs must be a dict") from e
    raise

Prevention

When it happens

Trigger: apply_workflow_inputs_to_workflow: matching_node_data.setdefault("inputs", {}) returns a value for which _is_mapping(inputs) is False.

Common situations: Hand-edited workflow JSON where 'inputs' is a list or string; exports from other tools using a different inputs representation; truncated or programmatically corrupted workflow documents.

Related errors


AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29). Data as JSON: /api/errors/986f0a92d8727dc0. Report an issue: GitHub.