Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

ZarrSource can't open an array whose GeoZarr metadata is on its parent group

Open
#813 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
38/100
Issue type
Feature
Clarity
Clearly specified
Activity status
Active
Tech stack
typescript
Domain
api

Research direction

Start in packages/deck.gl-zarr/src/zarr-source.ts at ZarrSource.open, following how variable is resolved and how geoZarrMetadata reaches the parser in packages/geozarr/src/parse.ts. Read examples/aef-mosaic/src/App.tsx for the working manual call that passes the root group's attributes. Done means open(root, { variable: "embeddings" }) reads the parent group's proj:/spatial: attributes, lets array attributes override them, leaves out the group's multiscales, and still lets geoZarrMetadata replace what open reads.

Written by the indexing model from the issue text.

Description

zarr

[!NOTE]
This issue was written by Claude (Claude Code), not by @kylebarron.

From the review of #812 (comment): ZarrSource should find the aef-mosaic example's GeoZarr metadata itself, perhaps by traversing child nodes.

Problem

The AEF store keeps its GeoZarr metadata on the root group: proj:code and all the spatial: keys. The data is embeddings, an int8 array directly inside the root. Its only attribute is _zarrs.

The conventions allow this layout. A group's proj: and spatial: attributes apply to the arrays directly inside it, but not to anything deeper, and an array can override them (proj, spatial).

ZarrSource.open reads a single node's attributes, so it can't open this store by itself. The example opens the array and passes the root's attributes along (App.tsx#L52-L64):

const root = await zarr.open.v3(store, { kind: "group" });
const opened = await zarr.open.v3(root.resolve(VARIABLE), {
  kind: "array",
});
if (!opened.is("int8")) {
  throw new Error(`Expected AEF embeddings to be int8, got ${opened.dtype}`);
}
// The GeoZarr metadata is on the root group, not on the array
const source = await ZarrSource.open(opened, {
  geoZarrMetadata: root.attrs,
});

I tried each way of calling open on an in-memory store with the same layout:

Call Result
ZarrSource.open(root) NotFoundError: Not found: v2 array. Metadata without multiscales describes one level at path "." (parse.ts#L105-L112), so open tries to open the root group as an array.
ZarrSource.open(root, { variable: "embeddings" }) NotFoundError: Not found: v2 group. variable must name a group (zarr-source.ts#L126-L129).
ZarrSource.open(embeddings) A ZodError for the missing spatial:dimensions.
ZarrSource.open(embeddings, { geoZarrMetadata: root.attrs }) Works.

Neither zarrita error says what's wrong.

Proposal

Let variable name an array as well as a group:

const root = await zarr.open.v3(store, { kind: "group" });
const source = await ZarrSource.open(root, { variable: "embeddings" });
  • variable names an array:
    • open reads the proj: and spatial: attributes of the group the array is in.
    • The array's own attributes override them.
    • It leaves out the group's multiscales, which describes the group's own levels.
  • variable names a group: nothing changes.
  • geoZarrMetadata still replaces whatever open would read.
  • ZarrSource.open(group): when the group's metadata has no multiscales, it fails with an error that asks for variable.

dynamical-zarr-ecmwf and nldas-icechunk also open their arrays themselves. They could use variable too, but their stores have no GeoZarr metadata, so they would keep passing geoZarrMetadata.

Questions

  1. How an array's attributes override its group's.

    • For proj:, the array's definition should replace the group's whole. A merge key by key could leave the group's proj:code beside the array's proj:wkt2, and the parser takes proj:code first (parse.ts#L34-L40).
    • For spatial:, the convention gives two rules. A group's properties apply to arrays "that don't define their own". Arrays can "override or supplement" them. A merge key by key fits "supplement", for example a group's spatial:dimensions with an array's spatial:transform.
  2. Checking the data type. The example opens the array partly to check opened.is("int8"), which makes the source a ZarrSource<"int8">. If open opens the array, the caller gets a ZarrSource<DataType>. Two ways to keep the check:

    • a type guard like zarrita's, source.is("int8");
    • a dtype option that open checks.

    Today ZarrSource.open<"int8">(group) compiles, but nothing checks it, since open casts the arrays it opens.

  3. Nested paths. For variable: "a/b/embeddings", the array's group is a/b. Should open open that group too? Without consolidated metadata, that takes one more read. The alternative is to accept only arrays directly inside node.

  4. An array passed as node. Should ZarrSource.open(embeddings) look for the array's group too? That also takes one more read, and with variable the caller can pass the group instead.

🤖 Written by Claude Code

Dominant language
TypeScript
Stars
232
Forks
34
Avg merge
1d 5h
Merged PRs (30d)
82

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from developmentseed/deck.gl-raster

All issues in developmentseed/deck.gl-raster

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.