huggingface/candle · error

unsupported auto_pad {s}

Error message

unsupported auto_pad {s}

What it means

candle-onnx's MaxPool only supports explicit padding: auto_pad must be absent or "NOTSET". Any other auto_pad value (SAME_UPPER, SAME_LOWER, VALID) has no implemented lowering and is rejected at eval time.

Source

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

                    }
                };
                values.insert(node.output[0].clone(), output);
            }
            "Dropout" => {
                let input = get(&node.input[0])?;
                // Do not apply dropout at the moment, consider that we're only doing inference.
                values.insert(node.output[0].clone(), input.clone());
            }
            "MaxPool" => {
                // https://github.com/onnx/onnx/blob/main/docs/Operators.md#MaxPool
                let dilations = get_attr_opt::<[i64]>(node, "dilations")?;
                let kernel_shape = get_attr::<[i64]>(node, "kernel_shape")?;
                let pads = get_attr_opt::<[i64]>(node, "pads")?;
                let strides = get_attr_opt::<[i64]>(node, "strides")?;
                let auto_pad = get_attr_opt::<str>(node, "auto_pad")?;
                match auto_pad {
                    None | Some("NOTSET") => (),
                    Some(s) => bail!("unsupported auto_pad {s}"),
                };
                if let Some(d) = dilations {
                    if d.iter().any(|&v| v != 1) {
                        bail!("MaxPool with dilation != 1, {dilations:?}")
                    }
                }
                if let Some(d) = pads {
                    if d.iter().any(|&v| v != 0) {
                        bail!("MaxPool with pads != 0, {pads:?}")
                    }
                }
                let xs = get(&node.input[0])?;
                let (k1, k2) = match kernel_shape {
                    [k1, k2] => (*k1 as usize, *k2 as usize),
                    _ => bail!("only 2d MaxPool is supported, kernel shape {kernel_shape:?}"),
                };
                let ys = match strides {
                    None => xs.max_pool2d((k1, k2))?,

View on GitHub (pinned to d5fee525bf)

Solutions

  1. Set the node's auto_pad attribute to "NOTSET" and provide explicit equivalent pads in the pads attribute
  2. Compute the SAME padding manually (pad = max(0, ceil(out/in)*k - in)) and pass it via pads, ensuring pads are all zero if needed by cropping/adjusting the input
  3. Pre-process the model with onnxsim / a graph rewrite that folds auto_pad into explicit pads

Example fix

# before (protobuf attr)
auto_pad: "SAME_UPPER"
# after
auto_pad: "NOTSET"
pads: [1, 1, 1, 1]
Defensive patterns

Strategy: validation

Validate before calling

fn ensure_no_autopad(node_attrs: &std::collections::HashMap<String, candle_onnx::protobuf::attribute_proto::AttributeType>) {
    if let Some(ap) = node_attrs.get("auto_pad") {
        assert!(matches!(ap, "NOTSET" | ""), "auto_pad {:?} unsupported", ap);
    }
}

Type guard

fn autopad_supported(auto_pad: Option<&str>) -> bool { matches!(auto_pad, None | Some("NOTSET")) }

Try / catch

match simple_eval(&model, inputs) {
    Ok(v) => v,
    Err(e) if e.to_string().contains("unsupported auto_pad") => {
        eprintln!("rewrite pooling node with explicit pads: {}", e); Default::default()
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Evaluating a MaxPool node whose auto_pad attribute is set to something other than NOTSET, e.g. "SAME_UPPER".

Common situations: Models exported from TensorFlow (which pads with SAME), PyTorch exports with padding='same', or TFLite→ONNX converters that set auto_pad.

Related errors


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