aggregate(values, by=<multiscale labels>) crashes with AttributeError despite DataTree being a declared input type
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 394
- Forks
- 95
- Avg merge
- 4d 3h
- Merged PRs (30d)
- 7
Description
[!NOTE]
This whole message is AI-generated. The issue was automatically discovered and reported by an AI agent (Claude) during an autonomous bug hunt on thespatialdatacode base. It has not been verified or triaged by a human yet; theneeds: triagelabel is set so that a maintainer can confirm it. The reproduction script below was executed by the agent in an isolated environment (see Environment) and its output is pasted verbatim.
Summary
Found while triaging #215/#216 (an existing tracking issue asking to add tests for aggregation with multiscale objects, and its follow-up listing unsupported values/by combinations). aggregate(values=<image>, by=<multiscale labels>) fails with AttributeError: 'DataTree' object has no attribute 'dtype', even though both the function signature and the label-aggregation code path treat DataTree as a supported by type for labels — the crash happens one level up, in the table-construction helper that was not updated for the DataTree case. Multiscale images in values (aggregated by single- or multiscale labels) work correctly and return the same result as the single-scale image.
Severity (agent's assessment): medium — crash on a documented/typed use case, no workaround other than manually collapsing to single-scale labels first
Where: src/spatialdata/_core/operations/aggregate.py::_create_sdata_from_table_and_shapes, line shapes_index_dtype = shapes.index.dtype if isinstance(shapes, GeoDataFrame) else shapes.dtype (~line 227); the type hint of the shapes parameter and of aggregate()'s by parameter both include DataTree, and _aggregate_image_by_labels already handles a DataTree by (it calls get_pyramid_levels(by, n=0) to get the finest scale before computing), but the result is then passed into _create_sdata_from_table_and_shapes still as the original DataTree.
Expected behaviour
aggregate(image, by=<multiscale labels>) returns the same table as aggregate(image, by=<the finest single-scale level of those labels>), instead of raising.
Reproduction
Save as repro.py and run uv run repro.py (the PEP 723 header pins spatialdata to the commit the bug was found on; replace the URL fragment with @main to test the current main branch).
# /// script
# requires-python = ">=3.12"
# dependencies = [
# "spatialdata @ git+https://github.com/scverse/spatialdata.git@ccf1ea048d054b6624214bf618008a9f9ae223e0",
# ]
# ///
"""New bug found while triaging #215/#216: `aggregate()` declares `by: DataTree` (multiscale labels) as
supported and `_aggregate_image_by_labels` handles it, but `_create_sdata_from_table_and_shapes` then
calls `shapes.dtype` on the DataTree -> AttributeError."""
import numpy as np
from spatialdata import aggregate
from spatialdata.models import Image2DModel, Labels2DModel
rng = np.random.default_rng(0)
img = Image2DModel.parse(rng.random((2, 32, 32)))
lab = np.zeros((32, 32), dtype=np.int32); lab[2:12, 2:12] = 5; lab[16:30, 16:30] = 9
labels_ms = Labels2DModel.parse(lab, scale_factors=[2, 2])
try:
t = aggregate(values=img, by=labels_ms, agg_func="mean")["table"]
print("aggregate(image, multiscale labels) -> OK", t.shape)
print("VERDICT: NOT REPRODUCED")
except Exception as e: # noqa: BLE001
print("aggregate(image, multiscale labels) ->", type(e).__name__, str(e)[:120])
print("VERDICT: REPRODUCED (multiscale labels in `by` crash with AttributeError although the signature declares DataTree support)")
Observed output
aggregate(image, multiscale labels) -> AttributeError 'DataTree' object has no attribute 'dtype'
VERDICT: REPRODUCED (multiscale labels in `by` crash with AttributeError although the signature declares DataTree support)
Possible fix direction (unverified)
In _create_sdata_from_table_and_shapes, resolve shapes to its finest single-scale level (e.g. via get_pyramid_levels(shapes, n=0), mirroring what _aggregate_image_by_labels already does) before reading .dtype/.index, or thread the resolved single-scale array through from the caller instead of the original DataTree.
Environment
uv run repro.py with the PEP 723 metadata in the script (fresh, isolated environment; spatialdata built from main @ ccf1ea0 (2026-08-28); Python 3.13, latest releases of the dependencies at run time: pandas 3.0, anndata 0.13, zarr 3.3, dask 2026.8, numpy 2.5, geopandas 1.1, shapely 2.1). macOS (arm64).
Possibly related issues
#215, #216
Automatically generated; discovered by an AI agent (Claude) and not yet reviewed by a human.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by running the provided repro.py with uv run, then inspect src/spatialdata/_core/operations/aggregate.py, especially _create_sdata_from_table_and_shapes near line 227 and the existing _aggregate_image_by_labels DataTree handling. Compare aggregation with multiscale labels against the finest single-scale level; done means the repro succeeds and both cases return the same table.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- data
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100