Skip to content

core GgufTensor::byte_size sizes Q4_1 at 18 bytes/block — it shares an arm with Q4_0; upstream Q4_1 is 20 #3453

Description

@noahgift

Found by the PMAT-3430 plan session on a re-run; verified independently on origin/main (2026-09-17). A sixth instance of the #3418 class: a private per-type size list that disagrees with the spec.

crates/aprender-core/src/format/gguf/types.rs, GgufTensor::byte_size:

GgmlType::Q4_0 | GgmlType::Q4_1 => {
    // Q4_0: 2 bytes scale + 16 bytes data = 18 bytes per 32 elements
    (elements as usize).div_ceil(32) * 18
}

Q4_1 carries a scale and a min (ggml_half d, m + 16 bytes): 20 bytes per 32 elements — static_assert(sizeof(block_q4_1) == 2*sizeof(ggml_half) + QK4_1/2) in ggml/src/ggml-common.h, and (32, 2 + 2 + 16) in gguf-py, both at llama.cpp 3173a5647 [X]. The comment in the arm describes Q4_0 only. Any Q4_1 tensor sized through this function is short by 2 bytes per block (10 %).

Not measured here: which paths consume this value for a Q4_1 tensor (export offsets, validation, allocation) and whether any real file is mis-written or mis-read today. That is the first task; the defect in the arithmetic is certain, its blast radius is [U].

Fix: split the arm; after #3430 the size comes from the one TRAITS table and this function has no numbers of its own.
Falsifier: a test asserting byte_size for a 32-element tensor of every GgmlType variant equals the C static_assert size at the pinned sha — RED on main today for Q4_1.
Relation to #3430: the plan session found that fixing this inside the enum merge breaks M1's "behaviour-preserving" promise (plan v4 moved it out to land first). Unslotted — milestone is the operator's call.

🤖 Generated with Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium prioritybugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions