huggingface/candle · error

input3 has to be contiguous

Error message

input3 has to be contiguous

What it means

Same Add3 contiguity check, applied to the third input (V-side tensor). The CPU parallel kernel slices raw storage using `contiguous_offsets()`; a strided layout on input3 cannot be safely read, so the op bails.

Source

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

        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;
                let s3_idx = b_idx * k_w;
                for h_idx in 0..k_h {
                    let s1_idx = s1_idx + h_idx * k_w;
                    let s2_idx = s2_idx + h_idx;
                    let dst_idx = h_idx * k_w;
                    for w_idx in 0..k_w {
                        let s1_idx = s1_idx + w_idx;
                        let s3_idx = s3_idx + w_idx;
                        let dst_idx = dst_idx + w_idx;
                        dst[dst_idx] = s1[s1_idx] + s2[s2_idx] + s3[s3_idx]

View on GitHub (pinned to d5fee525bf)

Solutions

  1. Call `.contiguous()?` on the third input before the op.
  2. Use the same idiom as neighboring code: `v.squeeze(0)?.transpose(0, 1)?.contiguous()?`.
  3. Audit any local modifications to image_encoder.rs that removed contiguous() calls.
  4. Run on the supported CPU path or let candle's standard ops (which handle strides) do the add instead of the fused op.

Example fix

// before
let v = values.squeeze(0)?.transpose(0, 1);
let out = add3(q, k, v)?;
// after
let out = add3(q, k, values.squeeze(0)?.transpose(0, 1)?.contiguous()?)?;
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 v = ensure_contiguous(&input3)?;

Type guard

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

Try / catch

match add3_forward(q, k, v) {
    Ok(t) => t,
    Err(e) if e.to_string().contains("input3 has to be contiguous") => {
        add3_forward(q, k, v.contiguous()?)
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: The third argument of the add-by-broadcast op is non-contiguous — typically a transposed or narrowed value tensor fed into SAM's image-encoder attention add on CPU without `.contiguous()`.

Common situations: Seen when adapting value branches of attention (e.g. squeezing/transposing v) and skipping materialization, or when chaining views across ops that PyTorch would handle lazily but this raw-pointer kernel cannot.

Related errors


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