tracel-ai/burn · error

int_matmul: unsupported dtype

Error message

int_matmul: unsupported dtype {:?}

What it means

int_matmul performs integer matrix multiplication but only supports I32 and I64 dtypes; the match panics for all others (I8/I16, unsigned U8..U64, floats, Bool). Operands must also share the same inner (K) dimension, enforced by an assert just above the panic.

Solutions

  1. Cast both operands to I32 or I64 before the matmul: a.cast::<i32>().matmul(b.cast::<i32>()).
  2. For int8 quantized workloads, upcast to i32 (standard practice to avoid accumulation overflow anyway).
  3. For float tensors, use the float matmul path instead of int_matmul.
  4. Add a dtype assert on both operands before entering the matmul helper.

Example fix

// before
let out = w_u8.matmul(x_u8); // U8 -> panic
// after
let out = w_u8.cast::<i32>().matmul(x_u8.cast::<i32>());
Defensive patterns

Strategy: validation

Validate before calling

assert!(matches!(lhs.dtype(), DType::I32 | DType::I64) && matches!(rhs.dtype(), DType::I32 | DType::I64), "int_matmul supports only I32/I64, got {:?} and {:?}", lhs.dtype(), rhs.dtype());

Type guard

fn is_int_matmul_compatible(t: &FlexTensor) -> bool { matches!(t.dtype(), DType::I32 | DType::I64) }

Prevention

When it happens

Trigger: Calling int matmul with operands of dtype I8/I16 or any unsigned dtype (U8/U16/U32/U64), or passing float tensors to the int matmul path.

Common situations: Quantized inference with int8 weights/activations; image tensors (u8) fed into an integer linear layer; dtype mismatch between lhs (i32) and rhs (u8) so lhs itself is fine but patterns like casting only one operand mislead; porting numpy int matmuls with 16-bit types.

Related errors


AI-assisted analysis of tracel-ai/burn@d16f7ba2ed (2026-09-05). Data as JSON: /api/errors/1c005addda5b264c. Report an issue: GitHub.

Appendix: source

Thrown at crates/burn-flex/src/ops/matmul.rs:516

pub fn int_matmul(lhs: FlexTensor, rhs: FlexTensor) -> FlexTensor {
    assert_eq!(lhs.dtype(), rhs.dtype(), "int_matmul: dtype mismatch");

    let lhs_shape = lhs.layout().shape();
    let rhs_shape = rhs.layout().shape();
    let lhs_rank = lhs_shape.num_dims();
    let rhs_rank = rhs_shape.num_dims();

    assert!(lhs_rank >= 2, "int_matmul requires at least 2D tensors");
    assert!(rhs_rank >= 2, "int_matmul requires at least 2D tensors");

    let k_lhs = lhs_shape[lhs_rank - 1];
    let k_rhs = rhs_shape[rhs_rank - 2];
    assert_eq!(k_lhs, k_rhs, "int_matmul: inner dimensions must match");

    match lhs.dtype() {
        DType::I32 => matmul_i32(lhs, rhs),
        DType::I64 => matmul_i64(lhs, rhs),
        _ => panic!("int_matmul: unsupported dtype {:?}", lhs.dtype()),
    }
}

/// i32 matmul using naive triple loop with SIMD dot product.
fn matmul_i32(lhs: FlexTensor, rhs: FlexTensor) -> FlexTensor {
    let lhs = lhs.to_contiguous();
    let rhs = rhs.to_contiguous();

    let lhs_shape = lhs.layout().shape();
    let rhs_shape = rhs.layout().shape();
    let lhs_rank = lhs_shape.num_dims();
    let rhs_rank = rhs_shape.num_dims();

    if lhs_rank == 2 && rhs_rank == 2 {
        matmul_2d_i32(&lhs, &rhs)
    } else {
        matmul_batched_i32(lhs, rhs)
    }

View on GitHub (pinned to d16f7ba2ed)