janhq/jan · error · io::Error

tensor claims dimensions

Error message

tensor {} claims {} dimensions

What it means

find_gguf_tensors rejects a tensor-info record whose n_dims exceeds MAX_TENSOR_DIMS (4, the GGML_MAX_DIMS value). GGUF tensors can never have more than 4 dimensions, so a larger rank means the byte walk has desynchronized or the file is corrupt, not that an exotic tensor shape exists.

Solutions

  1. Re-download or regenerate the model file and verify its checksum
  2. Confirm the file is GGUF version 2 or 3 (version < 2 is otherwise refused); use a hex dump on the first bytes
  3. Locate the corrupt tensor with llama.cpp's gguf_dump before re-converting
  4. If you control the file pipeline, check the exporter's dimension-count serialization

Example fix

// before
let bytes = std::fs::read("legacy-v1-model.gguf")?;
let found = find_gguf_tensors(Cursor::new(bytes), &wanted)?;
// after
let bytes = std::fs::read("model.gguf")?;
// ensure GGUF v2/v3: version stored as u32 LE at offset 4
let version = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
assert!(version >= 2, "convert v1 file first");
let found = find_gguf_tensors(Cursor::new(bytes), &wanted)?;
Defensive patterns

Strategy: validation

Validate before calling

fn is_supported_gguf_version(bytes: &[u8]) -> bool {
    bytes.len() >= 8
        && &bytes[0..4] == b"GGUF"
        && u32::from_le_bytes(bytes[4..8].try_into().unwrap()) >= 2
}
// v1 files desynchronize the walk; refuse them up front

Prevention

When it happens

Trigger: Calling find_gguf_tensors on a file where tensor i's u32 dimension count is > 4 - caused by corruption, a v1 file being read as v2 (u32 vs u64 layout shift), or misaligned parsing after a bad earlier record.

Common situations: Reading legacy GGUF v1 files, hand-edited or corrupted model files, feeding non-GGUF tensors, conversion bugs writing malformed tensor-info entries.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of janhq/jan@7205d770c1 (2026-09-17). Data as JSON: /api/errors/a082bf9b9e368bfa. Report an issue: GitHub.

Appendix: source

Thrown at src-tauri/plugins/tauri-plugin-llamacpp/src/gguf/helpers.rs:67

    }
    if meta.tensor_count > MAX_TENSORS {
        return Err(io::Error::new(
            io::ErrorKind::InvalidData,
            format!("tensor count {} is unreasonably large", meta.tensor_count),
        ));
    }

    let mut found: Vec<String> = Vec::new();
    for i in 0..meta.tensor_count {
        let name = read_gguf_string(&mut file).map_err(|e| {
            io::Error::new(
                io::ErrorKind::InvalidData,
                format!("Failed to read name for tensor {}: {}", i, e),
            )
        })?;
        let n_dims = file.read_u32::<LittleEndian>()?;
        if n_dims > MAX_TENSOR_DIMS {
            return Err(io::Error::new(
                io::ErrorKind::InvalidData,
                format!("tensor {} claims {} dimensions", i, n_dims),
            ));
        }
        // Read rather than seek: BufReader drops its buffer on every seek, so
        // skipping this way costs a syscall per tensor on a large model.
        for _ in 0..n_dims {
            file.read_u64::<LittleEndian>()?;
        }
        file.read_u32::<LittleEndian>()?; // ggml type
        file.read_u64::<LittleEndian>()?; // offset into the data section

        if wanted.contains(&name) && !found.contains(&name) {
            found.push(name);
            if found.len() == wanted.len() {
                break;
            }
        }

View on GitHub (pinned to 7205d770c1)