huggingface/candle · error

If node {:?} is malformed: branch outputs ({}) don't match n

Error message

If node {:?} is malformed: branch outputs ({}) don't match node outputs ({})

What it means

When evaluating an ONNX If node, candle-onnx validates that the chosen sub-graph (then_branch or else_branch) declares the same number of outputs as the If node itself. A mismatch means the graph is structurally malformed and the branch result cannot be bound to the node outputs.

Source

Thrown at candle-onnx/src/eval.rs:1174

                values.insert(node.output[0].clone(), output);
            }
            // https://github.com/onnx/onnx/blob/main/docs/Operators.md#identity
            "Identity" => {
                let input = get(&node.input[0])?;
                values.insert(node.output[0].clone(), input.clone());
            }
            // https://github.com/onnx/onnx/blob/main/docs/Operators.md#if
            "If" => {
                // protobuf encodes boolean false as 0 and true as 1
                let cond = to_scalar_flexible::<u8>(&get(&node.input[0])?.get(0)?)?;
                let attr_name = if cond != 0 {
                    "then_branch"
                } else {
                    "else_branch"
                };
                let sub_graph = get_attr::<GraphProto>(node, attr_name)?;
                if sub_graph.output.len() != node.output.len() {
                    bail!(
                        "If node {:?} is malformed: branch outputs ({}) don't match node outputs ({})",
                        node.name,
                        sub_graph.output.len(),
                        node.output.len()
                    );
                }
                let branch_out = simple_eval_(sub_graph, values)?;
                for (i, out) in node.output.iter().enumerate() {
                    values.insert(
                        out.clone(),
                        branch_out.get(&sub_graph.output[i].name).unwrap().clone(),
                    );
                }
            }
            // https://github.com/onnx/onnx/blob/main/docs/Operators.md#pad
            "Pad" => {
                let mode = get_attr_opt(node, "mode")?.unwrap_or("constant");
                let data = get(&node.input[0])?;

View on GitHub (pinned to d5fee525bf)

Solutions

  1. Fix the If node so both branches declare the same outputs as the If node (in count and order)
  2. Validate the model with onnx.checker / onnx.shape_inference to locate the malformed If
  3. Re-export the model from the source framework rather than editing the Protobuf by hand
  4. Run the ONNX optimizer pass that normalizes If sub-graph outputs

Example fix

// before: else_branch has 1 output, If node declares 2
// after: add the missing ValueInfoProto to else_branch.output so counts match
Defensive patterns

Strategy: validation

Validate before calling

for node in &graph.node {
    if node.op_type == "If" {
        for attr in ["then_branch", "else_branch"] {
            let g: &onnx_pb::GraphProto = get_attr(node, attr).unwrap();
            assert_eq!(g.output.len(), node.output.len(), "If {} {} output mismatch", node.name, attr);
        }
    }
}

Type guard

fn if_node_well_formed(node: &NodeProto, then_g: &GraphProto, else_g: &GraphProto) -> bool {
    then_g.output.len() == node.output.len() && else_g.output.len() == node.output.len()
}

Prevention

When it happens

Trigger: Evaluating a model with an If node whose selected sub_graph.output list length differs from node.output length (checked before the condition is even evaluated).

Common situations: Hand-assembled or tool-mangled control-flow graphs; exporters from frameworks with divergent branch output counts; an optimizer pass that removed outputs from one branch only.

Understand the failure class

Related errors


AI-assisted analysis of huggingface/candle@d5fee525bf (2026-09-02). Data as JSON: /api/errors/0b379f0640260412. Report an issue: GitHub.