diff --git a/xarray/core/datatree_io.py b/xarray/core/datatree_io.py index 33cf9ab84cc..f425170c271 100644 --- a/xarray/core/datatree_io.py +++ b/xarray/core/datatree_io.py @@ -211,12 +211,13 @@ def _datatree_to_zarr( writer = ArrayWriter() try: - for node in dt.subtree: + for rel_path, node in dt.subtree_with_keys: at_root = node is dt dataset = node.to_dataset(inherit=write_inherited_coords or at_root) - node_store = ( - root_store if at_root else root_store.get_child_store(node.path) - ) + # Use a relative path for group, because absolute paths are broken + # with consolidated metadata in zarr 3.1.2 and earlier: + # https://github.com/zarr-developers/zarr-python/pull/3428 + node_store = root_store if at_root else root_store.get_child_store(rel_path) dataset = node_store._validate_and_autodetect_region(dataset) node_store._validate_encoding(encoding) diff --git a/xarray/tests/test_backends_datatree.py b/xarray/tests/test_backends_datatree.py index 90e0a9740f4..de6c7499c9f 100644 --- a/xarray/tests/test_backends_datatree.py +++ b/xarray/tests/test_backends_datatree.py @@ -804,6 +804,17 @@ def assert_expected_zarr_files_exist( with open_datatree(str(storepath), engine="zarr") as written_dt: assert_identical(written_dt, original_dt) + @requires_dask + def test_rplus_mode( + self, tmp_path: Path, simple_datatree: DataTree, zarr_format: Literal[2, 3] + ) -> None: + storepath = tmp_path / "test.zarr" + original_dt = simple_datatree.chunk() + original_dt.to_zarr(storepath, compute=False, zarr_format=zarr_format) + original_dt.to_zarr(storepath, mode="r+") + with open_datatree(str(storepath), engine="zarr") as written_dt: + assert_identical(written_dt, original_dt) + @requires_dask def test_to_zarr_no_redundant_computation(self, tmpdir, zarr_format) -> None: import dask.array as da