huggingface/candle · error
seqlens_q has to be contiguous
Error message
seqlens_q has to be contiguous
What it means
The varlen path requires seqlens_q to be a contiguous tensor so it can take a single flat slice via contiguous_offsets(). Non-contiguous layouts (strided/sliced views) cannot be handed to the kernel directly.
Source
Thrown at candle-flash-attn/src/lib.rs:488
k: &candle::CudaStorage,
k_l: &Layout,
v: &candle::CudaStorage,
v_l: &Layout,
is_bf16: bool,
) -> Result<(candle::CudaStorage, Shape)> {
// https://github.com/Dao-AILab/flash-attention/blob/184b992dcb2a0890adaa19eb9b541c3e4f9d2a08/csrc/flash_attn/flash_api.cpp#L327
let dev = q.device();
let out_shape = q_l.shape().clone();
let out_l = Layout::contiguous(&out_shape);
let (seqlens_q, seqlens_q_layout) = self.seqlens_q.storage_and_layout();
let seqlens_q = match &*seqlens_q {
candle::Storage::Cuda(c) => c.as_cuda_slice::<u32>()?, // Should be i32!
_ => candle::bail!("seqlens_q must be a cuda tensor"),
};
let seqlens_q = match seqlens_q_layout.contiguous_offsets() {
Some((o1, o2)) => seqlens_q.slice(o1..o2),
None => candle::bail!("seqlens_q has to be contiguous"),
};
let (seqlens_k, seqlens_k_layout) = self.seqlens_k.storage_and_layout();
let seqlens_k = match &*seqlens_k {
candle::Storage::Cuda(c) => c.as_cuda_slice::<u32>()?, // Should be i32!
_ => candle::bail!("seqlens_k must be a cuda tensor"),
};
let seqlens_k = match seqlens_k_layout.contiguous_offsets() {
Some((o1, o2)) => seqlens_k.slice(o1..o2),
None => candle::bail!("seqlens_k has to be contiguous"),
};
let block_table = if let Some(block_table) = self.block_table.as_ref() {
let (block_table_storage, block_table_layout) = block_table.storage_and_layout();
match &*block_table_storage {
candle::Storage::Cuda(_) => {}
_ => candle::bail!("block_table must be a cuda tensor"),
}View on GitHub (pinned to d5fee525bf)
Solutions
- Call .contiguous() on seqlens_q before passing it
- Build seqlens fresh as a flat 1D contiguous tensor (Tensor::new/from_vec gives contiguous layout)
- Avoid narrow/slice views for seqlens; copy the needed values into a new tensor
Example fix
// before let seqlens_q = padded_seqlens.narrow(1, 0, batch + 1)?; // non-contiguous view // after let seqlens_q = padded_seqlens.narrow(1, 0, batch + 1)?.contiguous()?;
Defensive patterns
Strategy: validation
Validate before calling
fn ensure_contiguous(t: &Tensor) -> candle::Result<Tensor> {
if t.is_contiguous() { Ok(t.clone()) } else { t.contiguous() }
}
let seqlens_q = ensure_contiguous(&seqlens_q)?; Type guard
fn contiguous_cuda_u32(t: &Tensor) -> bool {
t.is_contiguous() && t.device().is_cuda() && t.dtype() == candle::DType::U32
} Try / catch
match flash_attn_varlen(&q, &k, &v, &seqlens_q.contiguous()?, &seqlens_k.contiguous()?, scale, max_q, max_k, None, None, None) {
Err(e) if e.to_string().contains("has to be contiguous") => { /* log tensor layout, rebuild */ }
r => r?,
} Prevention
- Call .contiguous() on any tensor built from narrow/slice before kernel calls
- Prefer constructing seqlens fresh via Tensor::from_vec (always contiguous)
- Avoid storing seqlens as views of larger buffers
When it happens
Trigger: Passing seqlens_q produced by narrow/slice/pad operations that leave a non-contiguous layout, or .transpose/.index_select views without .contiguous().
Common situations: Deriving cu_seqlens from a padded batch tensor by slicing rows/columns, reusing cached seqlens tensors that were reshaped with non-unit strides.
Related errors
- seqlens_k has to be contiguous
- seqlens_q has to be contiguous
- seqlens_k has to be contiguous
- seqlens_q must be a cuda tensor
- seqlens_k must be a cuda tensor
AI-assisted analysis of huggingface/candle@d5fee525bf (2026-09-02).
Data as JSON: /api/errors/6a87c67eb7f7ec44.
Report an issue: GitHub.