You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
3.3.0 picks between RegularChunkGridMetadata and RectilinearChunkGridMetadata from the values of the chunk edges rather than the form of the request. Since is_regular_1d counts "all chunks equal, last one smaller" as regular, an explicitly rectilinear spec whose edges happen to be uniform-plus-a-short-tail is stored as a regular grid.
For the array as created the two are equivalent. They diverge under resize: a FixedDimension grows by extending the uniform pattern, a VaryingDimension by appending an edge. The caller gets a grid that behaves differently from the one they asked for, with no warning and nothing in the metadata recording the substitution.
Why this matters
The use case is an append-only time series written in two regimes: a coarse backfill that lays down large chunks, then an incremental forward-fill that appends small ones. Rectilinear chunks make each appended window its own chunk, so the forward-fill never rewrites an edge chunk — that invariant is the entire reason for using them.
The collapse makes the invariant contingent on whether the initial backfill plan happens to look uniform. Edges of (168,) * 13 + (24,) become regular and every later append straddles a boundary; genuinely varied edges stay rectilinear and work. Same code, same intent, different outcome. With concurrent writers the shared-chunk rewrite is also a commit conflict rather than a clean append.
Origin
Introduced by #3899. 3.2.1's resolve_chunks dispatched on input syntax (_is_rectilinear_chunks), so a nested sequence always yielded a rectilinear grid; create_chunk_grid_metadata now dispatches on is_regular_nd after normalization to ChunksTuple. This reads as a side effect of consolidating the two normalization paths rather than an intended change — it's absent from the PR's "User-visible behavior changes" table, from changes/3899.bugfix.md, and from the 3.3.0 release notes.
Possible resolutions
There's no way today to request a rectilinear grid independently of the edge values; init_array calls create_chunk_grid_metadata(outer_chunks) with no override.
Honor the requested kind — a nested-sequence chunks yields a rectilinear grid even when the edges are uniform. Restores 3.2.x behavior.
Accept explicit grid metadata (or a chunk_grid="rectilinear" hint) in create_array.
Filing as design feedback against #4025, before rectilinear chunks leave experimental.
Steps to reproduce
# /// script# requires-python = ">=3.12"# dependencies = [# "zarr@git+https://github.com/zarr-developers/zarr-python.git@main",# ]# ///## This script automatically imports the development branch of zarr to check for issuesimporthashlibimportzarrzarr.config.set({"array.rectilinear_chunks": True})
store: dict[str, object] = {}
a=zarr.create_array(
store=store, shape=(24,), chunks=[[10, 10, 4]], dtype="float32", zarr_format=3
)
print("at create: ", a.metadata.chunk_grid)
deftouched(start: int, stop: int, val: int) ->list[str]:
"""Chunk keys created or modified by writing a[start:stop]."""defsnap() ->dict[str, str]:
return {
k: hashlib.md5(bytes(v.to_bytes())).hexdigest()
fork, vinstore.items()
ifk.startswith("c/")
}
before=snap()
a[start:stop] =valafter=snap()
returnsorted(kforkinafterifafter[k] !=before.get(k))
print("write [20:24]", touched(20, 24, 2))
a.resize((34,)) # append a fourth 10-wide chunkprint("after resize:", a.metadata.chunk_grid)
appended=touched(24, 34, 3)
print("write [24:34]", appended)
assertappended== ["c/3"], (
f"expected the appended region to be exactly one new chunk, got {appended}"
)
On main:
at create: RegularChunkGridMetadata(chunk_shape=(10,))
write [20:24] ['c/2']
after resize: RegularChunkGridMetadata(chunk_shape=(10,))
write [24:34] ['c/2', 'c/3']
AssertionError: expected the appended region to be exactly one new chunk, got ['c/2', 'c/3']
Swapping the dependency to zarr==3.2.1 passes, and shows the grid the spec asked for:
at create: RectilinearChunkGridMetadata(chunk_shapes=((10, 10, 4),))
write [20:24] ['c/2']
after resize: RectilinearChunkGridMetadata(chunk_shapes=((10, 10, 4, 10),))
write [24:34] ['c/3']
Zarr version
v3.3.0
Numcodecs version
v0.16.5
Python Version
3.12.13
Operating System
Mac
Installation
Using Pixi into virtual environment
Description
3.3.0 picks between RegularChunkGridMetadata and RectilinearChunkGridMetadata from the values of the chunk edges rather than the form of the request. Since is_regular_1d counts "all chunks equal, last one smaller" as regular, an explicitly rectilinear spec whose edges happen to be uniform-plus-a-short-tail is stored as a regular grid.
For the array as created the two are equivalent. They diverge under resize: a FixedDimension grows by extending the uniform pattern, a VaryingDimension by appending an edge. The caller gets a grid that behaves differently from the one they asked for, with no warning and nothing in the metadata recording the substitution.
Why this matters
The use case is an append-only time series written in two regimes: a coarse backfill that lays down large chunks, then an incremental forward-fill that appends small ones. Rectilinear chunks make each appended window its own chunk, so the forward-fill never rewrites an edge chunk — that invariant is the entire reason for using them.
The collapse makes the invariant contingent on whether the initial backfill plan happens to look uniform. Edges of (168,) * 13 + (24,) become regular and every later append straddles a boundary; genuinely varied edges stay rectilinear and work. Same code, same intent, different outcome. With concurrent writers the shared-chunk rewrite is also a commit conflict rather than a clean append.
Origin
Introduced by #3899. 3.2.1's resolve_chunks dispatched on input syntax (_is_rectilinear_chunks), so a nested sequence always yielded a rectilinear grid; create_chunk_grid_metadata now dispatches on is_regular_nd after normalization to ChunksTuple. This reads as a side effect of consolidating the two normalization paths rather than an intended change — it's absent from the PR's "User-visible behavior changes" table, from changes/3899.bugfix.md, and from the 3.3.0 release notes.
Possible resolutions
There's no way today to request a rectilinear grid independently of the edge values; init_array calls create_chunk_grid_metadata(outer_chunks) with no override.
appendmethod toVaryingDimensionfor explicit chunk extension #3870, which already raises this exact question.Filing as design feedback against #4025, before rectilinear chunks leave experimental.
Steps to reproduce
On main:
Swapping the dependency to zarr==3.2.1 passes, and shows the grid the spec asked for:
Additional output
No response