{"record":{"id":"8c045b7251056d93","repo":"janhq/jan","slug":"array-length-is-unreasonably-large","errorCode":null,"errorMessage":"Array length {} is unreasonably large","messagePattern":"Array length (.+?) is unreasonably large","errorType":"validation","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"src-tauri/plugins/tauri-plugin-llamacpp/src/gguf/helpers.rs","lineNumber":99,"sourceCode":"        GgufValueType::Uint8 => Ok(reader.read_u8()?.to_string()),\n        GgufValueType::Int8 => Ok(reader.read_i8()?.to_string()),\n        GgufValueType::Uint16 => Ok(reader.read_u16::<LittleEndian>()?.to_string()),\n        GgufValueType::Int16 => Ok(reader.read_i16::<LittleEndian>()?.to_string()),\n        GgufValueType::Uint32 => Ok(reader.read_u32::<LittleEndian>()?.to_string()),\n        GgufValueType::Int32 => Ok(reader.read_i32::<LittleEndian>()?.to_string()),\n        GgufValueType::Float32 => Ok(reader.read_f32::<LittleEndian>()?.to_string()),\n        GgufValueType::Bool => Ok((reader.read_u8()? != 0).to_string()),\n        GgufValueType::String => read_gguf_string(reader),\n        GgufValueType::Uint64 => Ok(reader.read_u64::<LittleEndian>()?.to_string()),\n        GgufValueType::Int64 => Ok(reader.read_i64::<LittleEndian>()?.to_string()),\n        GgufValueType::Float64 => Ok(reader.read_f64::<LittleEndian>()?.to_string()),\n        GgufValueType::Array => {\n            let elem_type_u32 = reader.read_u32::<LittleEndian>()?;\n            let elem_type = GgufValueType::try_from(elem_type_u32)?;\n            let len = reader.read_u64::<LittleEndian>()?;\n\n            if len > 1_000_000 {\n                return Err(io::Error::new(\n                    io::ErrorKind::InvalidData,\n                    format!(\"Array length {} is unreasonably large\", len),\n                ));\n            }\n\n            if len > 24 {\n                skip_array_data(reader, elem_type, len)?;\n                return Ok(format!(\n                    \"<Array of type {:?} with {} elements, data skipped>\",\n                    elem_type, len\n                ));\n            }\n\n            let mut elems = Vec::with_capacity(len as usize);\n            for _ in 0..len {\n                elems.push(read_gguf_value(reader, elem_type)?);\n            }\n            Ok(format!(\"[{}]\", elems.join(\", \")))","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/janhq/jan/blob/fad3f12a147d138388a66f0d92a02b2675f65294/src-tauri/plugins/tauri-plugin-llamacpp/src/gguf/helpers.rs#L81-L117","documentation":"Returned by `read_gguf_value` when an `Array` value's element count (u64 LE) exceeds 1,000,000. Arrays in GGUF metadata (e.g. tokenizer merges, vocabulary) can be large but should not exceed this cap; the guard prevents allocating and iterating an attacker-controlled huge count.","triggerScenarios":"Decoding an `Array` value whose length field decodes above 1,000,000. The most common cause is stream misalignment: the element-type u32 or the length u64 was read from the wrong offset because a prior field had the wrong width. A genuinely huge array (very large tokenizer) could also trip it but is uncommon.","commonSituations":"Misalignment after skipping a previous array whose element stride was wrong; a corrupted file; a malformed GGUF produced by a buggy converter. Note that arrays of length > 24 are already skipped (`skip_array_data`), so the cap is specifically about refusing pathological counts before the skip loop.","solutions":["Audit `skip_array_data` against the GGUF spec for the offending element type to confirm the skip uses the correct byte width.","Hex-dump the region around the failure to see whether the length looks plausible.","If the array is legitimately large (a big tokenizer), raise the cap to a value that comfortably covers real files (e.g. 10,000,000).","Verify checksum and re-download if corrupted."],"exampleFix":"// before\nif len > 1_000_000 {\n    return Err(io::Error::new(InvalidData, format!(\"Array length {} is unreasonably large\", len)));\n}\n\n// after - cap with context\nconst MAX_ARRAY_LEN: u64 = 10_000_000;\nif len > MAX_ARRAY_LEN {\n    return Err(io::Error::new(InvalidData,\n        format!(\"array length {} exceeds cap {} (suspect misalignment)\", len, MAX_ARRAY_LEN)));\n}","handlingStrategy":"validation","validationCode":"const MAX_ARRAY: u64 = 1_000_000;\nfn safe_array_len(reader: &mut impl ReadBytesExt) -> Option<u64> {\n    reader.read_u64::<LittleEndian>().ok().filter(|&n| n <= MAX_ARRAY)\n}","typeGuard":"null","tryCatchPattern":"match read_gguf_value(reader, value_type) {\n    Ok(v) => Ok(v),\n    Err(e) if e.to_string().contains(\"Array length\") => {\n        Err(CorruptFile(\"oversized array length\".into()))\n    }\n    Err(e) => Err(e.into()),\n}","preventionTips":["Audit `skip_array_data` element strides against the GGUF spec when adding new element types.","Verify checksums to catch corruption early.","Use a known-good reference file when changing the array path."],"tags":["gguf","array","memory","validation","llamacpp","rust"],"backgroundTag":null,"analyzedSha":"fad3f12a147d138388a66f0d92a02b2675f65294","analyzedAt":"2026-08-12T20:33:47.516Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}