fix(io): fail fast on unsupported GGUF tensor types; load Q4_0/Q5_0/Q5_1 packed (#919) - #925
Merged
Merged
Conversation
…5_1 packed StreamingGgufParametersLoader silently skipped any tensor type outside its when-expression — a SKIP progress string was the only signal, the load 'succeeded' with missing weights, and the failure surfaced far away in the forward pass (the load-time half of #654). The deprecated legacy loader already hard-failed here; the streaming loader regressed that. Two gaps hid in that else branch: - Truly unsupported types (e.g. Q4_1): an eager pre-scan of the tensor directory now throws IllegalArgumentException before any tensor is delivered, naming every offending tensor, its type (raw value for unknown types), and the supported set. The per-tensor else becomes a hard error guarding drift from the new SUPPORTED_TENSOR_TYPES companion set, which both checks derive from. - Q4_0 / Q5_0 / Q5_1 had packed TensorData (fromRawBytes) and matmul kernels but were absent from the loader — they now load as packed blocks like Q8_0/Q4_K instead of being skipped. Dtype-policy mismatches (e.g. an I32 tensor under an FP32 load) keep the existing skip-via-null behavior — that path is a filter, not an error. Behavior change: files that previously 'loaded' with skipped tensors now fail at load, matching the RFC's fail-before-execution rule already applied by validatePolicy/withPolicy. Verified: jvmTest (6 loader + 5 new fail-fast + 8 policy tests green), linuxX64Test green (commonMain/commonTest on Kotlin/Native), io-core jvmTest green (downstream GGUF fixture loads unaffected). Closes #919 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
aharakal
previously approved these changes
Aug 10, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
StreamingGgufParametersLoadersilently skipped any tensor type outside itswhen— aSKIPprogress string was the only signal, the load "succeeded" with missing weights, and the failure surfaced far away in graph build / the first forward pass (the load-time half of #654). The deprecated legacyGgufParametersLoaderalready hard-failed here; the streaming loader regressed that. Full analysis in #919.Two distinct gaps hid in that
else:IllegalArgumentExceptionbefore any tensor is delivered, naming every offending tensor, its type (raw on-disk value for unknown types, truncated listing past 8 offenders), and the supported set:TensorData(fromRawBytes) and matmul kernels but were missing from the loader'swhen— a Q4_0 GGUF (a first-class kernel format) loaded with missing weights. They now load as packed blocks, mirroring the Q8_0/Q4_K branches.Design notes
whenanchor on a newSUPPORTED_TENSOR_TYPEScompanion set; the per-tensorelseis now a hardIllegalStateExceptionthat names the drift if the two ever disagree.validatePolicy/withPolicyalready applies (its kdoc previously acknowledged this exact gap).Tests
StreamingGgufParametersLoaderFailFastTest(5 cases, runs on every target): supported set passes, Q4_1 rejected with tensor name + supported set, unknown raw type value reported verbatim, long offender lists truncated with a count, Q4_0/Q5_0/Q5_1 pinned in the supported set.onTensorLoadedcallback; multiple offenders all named; Q4_0/Q5_0/Q5_1 load asPackedBlockStorage. The existing GGUF-builder helper was parameterized to cover arbitrary tensor sets.Verified
:skainet-io:skainet-io-gguf:jvmTest— 19/19 green (6 loader + 5 fail-fast + 8 policy):skainet-io:skainet-io-gguf:linuxX64Test— green (commonMain + commonTest on Kotlin/Native):skainet-io:skainet-io-core:jvmTest— green (downstream GGUF fixture loads unaffected)Closes #919
🤖 Generated with Claude Code