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
- Call `.contiguous()?` on the third input before the op.
- Use the same idiom as neighboring code: `v.squeeze(0)?.transpose(0, 1)?.contiguous()?`.
- Audit any local modifications to image_encoder.rs that removed contiguous() calls.
- 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
- Always .contiguous() the value tensor after squeeze/transpose chains.
- Don't remove contiguous() calls from image_encoder.rs as a micro-optimization.
- Check layout contiguity with contiguous_offsets() before custom CPU kernels.
- Keep GPU/CPU dispatch paths separate and tested.
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
- input1 has to be contiguous
- input2 has to be contiguous
- input has to be contiguous
- alpha has to be contiguous
- input has to be contiguous
AI-assisted analysis of huggingface/candle@d5fee525bf (2026-09-02).
Data as JSON: /api/errors/0989ce9fdf0630ea.
Report an issue: GitHub.