janhq/jan · error · io::Error

Failed to read name for tensor

Error message

Failed to read name for tensor {}: {}

What it means

While walking the tensor-info block in find_gguf_tensors, the u64-prefixed name string for tensor i could not be read (bad length prefix, truncated file, or desynchronized stream). The wrapper re-tags the underlying I/O or UTF-8 error with the tensor index so the corrupt record is identified.

Solutions

  1. Re-download the model file and verify its checksum
  2. Ensure the reader you pass is seekable over the complete file (not a partial stream)
  3. Check the file is GGUF version >= 2; v1 files misparse and desynchronize the walk
  4. Use llama.cpp's gguf_dump to locate exactly where the file structure breaks

Example fix

// before
let f = std::fs::File::open("partial-shard-00001-of-00002.gguf")?;
let found = find_gguf_tensors(f, &wanted)?;
// after
let f = std::fs::File::open("model.gguf")?;
let meta = std::fs::metadata("model.gguf")?;
if meta.len() < expected_min_size { anyhow::bail!("file truncated; re-download"); }
let found = find_gguf_tensors(f, &wanted)?;
Defensive patterns

Strategy: validation

Validate before calling

fn file_looks_complete(path: &std::path::Path, min_bytes: u64) -> io::Result<bool> {
    Ok(std::fs::metadata(path)?.len() >= min_bytes)
}
// check before opening the reader for find_gguf_tensors

Prevention

When it happens

Trigger: Calling find_gguf_tensors on a file where the tensor-info block is truncated mid-name, the preceding walk desynchronized (bad version/dims), or a tensor name length prefix points past EOF.

Common situations: Partially downloaded GGUF shards (only first shard parsed), files spliced or edited by conversion scripts, v1 files or other formats misread as v2/v3, memory-corrupted model caches.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


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

Appendix: source

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

    // v1 sized strings and dimensions with u32s. llama.cpp refuses that
    // version outright, and reading it as v2 would invent names.
    if meta.version < 2 {
        return Err(io::Error::new(
            io::ErrorKind::InvalidData,
            format!("GGUF version {} has no readable tensor block", meta.version),
        ));
    }
    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

View on GitHub (pinned to 7205d770c1)