Conversation
…unk size of 0 `ShardingCodec.validate` checked its own inner chunk shape against the chunk grid but never validated the codecs that encode each inner chunk. A sharding codec nested in another one could therefore declare an inner chunk shape that does not divide the chunk it splits: the array was created and opened without error, and then read back wrong data or its fill value. `validate` now validates the inner codecs as array metadata validates its codecs: each against the chunk the codecs before it leave it (so permuted after a transpose), as a regular grid of one inner chunk. `ShardingCodec` also rejects an inner chunk size of 0 (or `False`) when it is constructed or unpickled, as tensorstore and zarrs do when they parse the codec configuration. It used to accept one, which raised a `ZeroDivisionError` when an array used the codec or, where the codec was nested, on the first write. Assisted-by: ClaudeCode:claude-fable-5.1
Assisted-by: ClaudeCode:claude-fable-5.1
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #4480 +/- ##
=======================================
Coverage 94.69% 94.69%
=======================================
Files 94 94
Lines 13598 13606 +8
=======================================
+ Hits 12876 12884 +8
Misses 722 722
🚀 New features to boost your workflow:
|
d-v-b
marked this pull request as ready for review
October 5, 2026 15:51
Contributor
Author
|
it's an important bugfix so I'm merging it. this change overlaps somewhat with the more comprehensive changes in #4352, but that's slated for 3.5.0 |
This branch has not been deployed
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.
This PR fixes a bug in the sharding codec that allowed the sharding codec to contain a second sharding codec with an incompatible chunk shape. the sharding codec also accepted an inner chunk edge of 0, which is inane and rejected at construction now.
🤖 AI text below 🤖
A sharding codec nested in the codecs of another sharding codec is now validated as the outer one is: its inner chunk shape must divide the chunk it encodes. Such an array used to be created, and opened, without error, and then read back wrong data or its fill value.
ShardingCodecnow rejects an inner chunk size of 0 (orFalse) when it is constructed, with aValueErrorthat names the dimension, as other Zarr implementations do; it used to accept one, which raised aZeroDivisionErrorwhen an array was created or opened with the codec or, where the codec was nested in another sharding codec, on the first write to the array.Closes #4437.
Problem
Found by an agent audit of chunk handling on
mainthat followed #4374, looking for other places where an invalid chunk declaration is accepted, stored, and only fails (or misreads) later.ShardingCodec.validatechecks its ownchunk_shapeagainst the array's chunk grid, but never validated the codecs that encode each inner chunk. Onmain:With a nested
chunk_shape=(12, 40)everything reads back as the fill value, and with(0, 5)the array is created,[0, 5]is stored, the array reopens, and the first write raisesZeroDivisionError. The same shapes given to a top-level sharding codec were already rejected ((0, 5)with a bareZeroDivisionError).Changes
ShardingCodec.validatevalidates its inner codecs the wayArrayV3Metadatavalidates an array's codecs: each one against the chunk the codecs before it leave it (so permuted after a transpose, and with the data type a cast leaves), as a regular grid of one inner chunk. A nested sharding codec is thereby checked against the chunk it splits, at create and at open.ShardingCodec.__init__and__setstate__parse the inner chunk shape as a shape whose every size is a chunk edge length (parse_chunk_shape(parse_shapelike(...))), so 0 andFalseare rejected. NumPy integers, a bare integer andTrueare accepted as before.tensorstore (
jb::Array(jb::Integer<Index>(1))in thesharding_indexedbinder) and zarrs (ChunkShape = Vec<NonZeroU64>) both reject a 0 when they parse the codec configuration.Behaviour changes to review
ShardingCodec(chunk_shape=(0,))no longer constructs. fix(chunk-grids): require chunk sizes of at least 1 and read the 0, false and true sizes older releases stored #4334 pinned it as constructible intest_pickle; that case is removed. No array could use such a codec:validateraisedZeroDivisionErrorfor it.ArrayV2Metadata(chunks=(0,))is unchanged: it is still accepted and written as given, as fix(chunk-grids): require chunk sizes of at least 1 and read the 0, false and true sizes older releases stored #4334 documents. The two(0,)/(False,)cases oftest_chunk_shape_read_as_array_shapethat covered both classes moved to a Zarr format 2 only test.Tests
test_nested_sharding_roundtrip: valid nested sharding (dividing, equal, after a transpose, three levels) is still accepted and round-trips.test_nested_sharding_rejects_indivisible_inner_chunk_shape: rejected at create, store untouched.test_open_rejects_stored_nested_sharding_with_indivisible_inner_chunk_shape: a stored document is rejected when parsed.test_sharding_codec_rejects_inner_chunk_size_zero: constructor rejection.The full suite and
prek run --all-filespass locally.Relation to other open PRs
This PR is a small stopgap for the data corruption reported in #4437. Two larger open PRs overlap with it:
_validate_inner_codecsmethod added here and needs a rebase over this PR if this one merges first.ShardingCodec(chunk_shape=...). It supersedes the constructor check added here, and goes further (ArrayV2Metadata, bools, NumPy integers).Not fixed here, and left to #4352: a top-level sharding codec placed after a transpose is still checked against the untransposed chunk grid.
Author attestation
TODO
docs/user-guide/*.mdchanges/🤖 Generated with Claude Code