huggingface/candle · error

dim {dim} is odd

Error message

dim {dim} is odd

What it means

The rope() helper in flux/model.rs computes rotary position embeddings by splitting the dimension into even/odd halves, so it requires dim to be even. If an odd head dimension reaches it, bail! returns Err("dim {dim} is odd") instead of producing a broken frequency table.

Source

Thrown at candle-transformers/src/models/flux/model.rs:82

fn scaled_dot_product_attention(q: &Tensor, k: &Tensor, v: &Tensor) -> Result<Tensor> {
    let dim = q.dim(D::Minus1)?;
    let scale_factor = 1.0 / (dim as f64).sqrt();
    let mut batch_dims = q.dims().to_vec();
    batch_dims.pop();
    batch_dims.pop();
    let q = q.flatten_to(batch_dims.len() - 1)?;
    let k = k.flatten_to(batch_dims.len() - 1)?;
    let v = v.flatten_to(batch_dims.len() - 1)?;
    let attn_weights = (q.matmul(&k.t()?)? * scale_factor)?;
    let attn_scores = candle_nn::ops::softmax_last_dim(&attn_weights)?.matmul(&v)?;
    batch_dims.push(attn_scores.dim(D::Minus2)?);
    batch_dims.push(attn_scores.dim(D::Minus1)?);
    attn_scores.reshape(batch_dims)
}

fn rope(pos: &Tensor, dim: usize, theta: usize) -> Result<Tensor> {
    if dim % 2 == 1 {
        candle::bail!("dim {dim} is odd")
    }
    let dev = pos.device();
    let theta = theta as f64;
    let inv_freq: Vec<_> = (0..dim)
        .step_by(2)
        .map(|i| 1f32 / theta.powf(i as f64 / dim as f64) as f32)
        .collect();
    let inv_freq_len = inv_freq.len();
    let inv_freq = Tensor::from_vec(inv_freq, (1, 1, inv_freq_len), dev)?;
    let inv_freq = inv_freq.to_dtype(pos.dtype())?;
    let freqs = pos.unsqueeze(2)?.broadcast_mul(&inv_freq)?;
    let cos = freqs.cos()?;
    let sin = freqs.sin()?;
    let out = Tensor::stack(&[&cos, &sin.neg()?, &sin, &cos], 3)?;
    let (b, n, d, _ij) = out.dims4()?;
    out.reshape((b, n, d, 2, 2))
}

View on GitHub (pinned to d5fee525bf)

Solutions

  1. Make hidden_size divisible by num_attention_heads such that head_dim is even (e.g. hidden_size 3072 / heads 12 -> 256).
  2. Check the Config you pass to FluxModel and revert any custom modifications to standard Flux dimensions.
  3. If you call rope directly, ensure you pass an even dim (typically the even head_dim from the attention layer).

Example fix

// before
let config = Config { hidden_size: 1537, num_attention_heads: 4, .. };
// head_dim = 1537/4 -> odd downstream
// after
let config = Config { hidden_size: 1536, num_attention_heads: 4, .. };
// head_dim = 384 (even), rope() succeeds
Defensive patterns

Strategy: validation

Validate before calling

let head_dim = config.hidden_size / config.num_attention_heads;
if head_dim % 2 != 0 {
    return Err(anyhow::anyhow!("head_dim {head_dim} is odd; rope requires even dim"));
}

Type guard

fn is_even_dim(dim: usize) -> bool { dim % 2 == 0 }

Try / catch

match rope(&pos, head_dim, theta) {
    Ok(freqs) => freqs,
    Err(e) if e.to_string().ends_with("is odd") => {
        anyhow::bail!("fix model config so hidden_size/num_heads is even: {e}")
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Calling rope(pos, dim, theta) with an odd dim — practically, a Fluxmodel built with config.hidden_size not divisible by the number of attention heads, giving an odd per-head head_dim that flows through forward -> rope.

Common situations: Hand-editing Flux model config (hidden_size or num_attention_heads) so hidden_size/num_heads is odd; using a custom/modified Flux variant with an unusual embedding width.

Related errors


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