huggingface/candle · error

input1 has to be contiguous

Error message

input1 has to be contiguous

What it means

The SAM image encoder's custom Add3 (add-by-broadcast) op implements a fast CPU path that indexes raw f32 data via `contiguous_offsets()`. When the first input layout has no contiguous offset range (tensor is strided/non-contiguous, e.g. after transpose or slicing), slicing raw data would be wrong, so it bails with 'input1 has to be contiguous'.

Source

Thrown at candle-transformers/src/models/segment_anything/image_encoder.rs:64

    fn name(&self) -> &'static str {
        "add3"
    }

    fn cpu_fwd(
        &self,
        s1: &candle::CpuStorage,
        l1: &candle::Layout,
        s2: &candle::CpuStorage,
        l2: &candle::Layout,
        s3: &candle::CpuStorage,
        l3: &candle::Layout,
    ) -> Result<(candle::CpuStorage, candle::Shape)> {
        use rayon::prelude::*;

        let Add3(b, q_h, q_w, k_h, k_w) = *self;
        let s1 = s1.as_slice::<f32>()?;
        let s1 = match l1.contiguous_offsets() {
            None => candle::bail!("input1 has to be contiguous"),
            Some((o1, o2)) => &s1[o1..o2],
        };
        let s2 = s2.as_slice::<f32>()?;
        let s2 = match l2.contiguous_offsets() {
            None => candle::bail!("input2 has to be contiguous"),
            Some((o1, o2)) => &s2[o1..o2],
        };
        let s3 = s3.as_slice::<f32>()?;
        let s3 = match l3.contiguous_offsets() {
            None => candle::bail!("input3 has to be contiguous"),
            Some((o1, o2)) => &s3[o1..o2],
        };
        let mut dst = vec![0f32; b * q_h * q_w * k_h * k_w];
        dst.par_chunks_exact_mut(k_h * k_w)
            .enumerate()
            .for_each(|(b_idx, dst)| {
                let s1_idx = b_idx * k_h * k_w;
                let s2_idx = b_idx * k_h;

View on GitHub (pinned to d5fee525bf)

Solutions

  1. Call `.contiguous()?` on the offending input tensor before the op that feeds Add3.
  2. Use `.transpose(0,1)?.contiguous()?` (as done elsewhere in this file) to materialize strided views.
  3. If you changed model code to remove a contiguous() for speed, restore it or add a strided-kernel path.
  4. Ensure you're on the CPU path the op supports; GPU dispatch uses a different kernel.

Example fix

// before
let x = q.transpose(0, 1);
let out = add3(x, k, v)?;
// after
let out = add3(q.transpose(0, 1)?.contiguous()?, k, v)?;
Defensive patterns

Strategy: validation

Validate before calling

fn ensure_contiguous(t: &Tensor) -> candle::Result<Tensor> {
    if t.layout().contiguous_offsets().is_none() { t.contiguous() } else { Ok(t.clone()) }
}
let q = ensure_contiguous(&input1)?;

Type guard

fn is_contiguous(t: &Tensor) -> bool {
    t.layout().contiguous_offsets().is_some()
}

Try / catch

match add3_forward(x1, x2, x3) {
    Ok(t) => t,
    Err(e) if e.to_string().contains("has to be contiguous") => {
        add3_forward(x1.contiguous()?, x2.contiguous()?, x3.contiguous()?)
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Calling the image encoder's forward with the first of the three summed tensors (the image embedding/Q side) in a non-contiguous layout — typically the direct result of `transpose`, `permute`, `narrow`, or `broadcast` without an intervening `.contiguous()` call, on the CPU backend.

Common situations: Hitting this after modifying SAM internals to skip a `.contiguous()` call for performance; passing transposed key tensors into the attention add; combining tensors produced by broadcasting that were never materialized.

Related errors


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