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
This whole message is AI-generated. The issue was automatically discovered and reported by an AI agent (Claude) during an autonomous bug hunt on the spatialdata code base. It has not been verified or triaged by a human yet; the needs: triage label 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
Each item was confirmed with a script; the repro below demonstrates items 1–8.
Empty GeoDataFrame → IndexError in ShapesModel.parse and get_axes_names (.iloc[0]) instead of the ValueError("Column geometry is empty") that validate would raise.
TableModel.parse(region=("a", "b")) (tuple) fails with the misleading adata.obs[region] values do not match with region values; region=pd.Index([...]) fails with TypeError: unhashable type: 'Index'. Only list/np.ndarray are normalised.
RasterSchema.parse(chunks=<float>) crashes with ValueError: not enough values to unpack ({dim: chunks for index, dim in data.dims} iterates dimension names).
RasterSchema.parse(DataArray) mutates its input: a numpy-backed DataArray has its .data replaced by a dask array in place.
PointsModel.validate rejects pandas nullable / pyarrow numeric coordinate dtypes (Int64, float64[pyarrow]) while accepting every numpy int/float — use pd.api.types.is_numeric_dtype.
get_element_instances(shapes_or_points, return_background=True) → TypeError: _() got an unexpected keyword argument (the GeoDataFrame/DaskDataFrame overloads lack the keyword the generic signature advertises).
set_table_annotates_spatialelement(region=pd.Series([...])) — the type hint allows a Series, but the Series object is stored in uns["spatialdata_attrs"]["region"]; TableModel.validate then fails with unhashable type: 'Series' and the table cannot be written.
filter_by_table_query(table_name, element_names=[...]) raises KeyError: 't' when no table row annotates the requested elements (subset(filter_tables=True) drops the empty table before sdata_subset.tables[table_name]).
Not in the script:
CLI: python -m spatialdata peek <store> table silently drops the tables — the click Choice offers "table" (singular) but read_zarr expects "tables", and tables is rejected by click.
TableModel.parse uniqueness check computes groupby(region).nunique() over all obs columns instead of only the instance key (10–100× slower; 0.35 s vs 0.02 s for 1 M rows × 54 columns). Use grouped[instance_key].nunique().
relabel_sequential breaks when the internal lookup array spans several dask chunks (max_label > ~16 M with the default chunk size): ValueError: Dimension 1 has N blocks, adjust_chunks specified with 1 blocks. rechunk(-1) the lookup array.
polygon_query(circles, clip=True) returns Polygon geometries but keeps the radius column.
to_polygons(circles) buffers row-by-row with DataFrame.apply(axis=1) (2.1 s for 167 k Xenium circles) whereas shapely.buffer(geoms, radii, quad_segs=...) takes 0.58 s with identical areas.
map_raster docstring: changing dimensionality needs drop_axis/new_axis (forwarded via **kwargs) in addition to dims; with only dims=("y", "x") the call fails with number of dimensions of the output data (3) differs....
get_transformation_between_landmarks docstring example uses PointsModel(points_moving) instead of PointsModel.parse(...); _get_current_output_axes contains a dead statement set(transformation.map_axis.keys()).
Compressor level docs inconsistent: _validate_compressor_args messages say 'between 1 and 9' in two places and 'between 0 and 9' in another; level 0 is accepted.
Docstring/signature mismatches: rasterize_bins documents return_regions_as_labels (parameter: return_region_as_labels); SpatialData.subset documents filter_table (parameter: filter_tables); validate_axes documents axis (parameter: axes); get_extent's generic docstring lists its parameters under 'Returns'; get_transformation_between_coordinate_systems does not document sdata/intermediate_coordinate_systems; the points↔geopandas converters do not document suppress_z_warning.
Forward compatibility: Pandas4Warning: The copy keyword is deprecated from table.obs.rename(columns=..., copy=False) in concatenate._concatenate_tables (will raise in pandas 4).
ShapesModel.validate inspects only the first geometry, so [Polygon, Point] without a radius column is accepted; validate_shapes_not_mixed_types exists but is opt-in.
Table filtering via left join computes da.unique on full-resolution labels in subset(), filter_by_coordinate_system() and spatial queries (0.1 s per 3648×5472 labels, 1.8 s for filter_by_coordinate_system on the 30-labels CosMx dataset); for filter_by_coordinate_system a name-based filter would be O(n_rows). (See also Bounding box query APIs slowed down by join operations #1177.)
Severity (agent's assessment): low (each item)
Where: various, see list
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).
1. empty GeoDataFrame -> IndexError instead of a clear ValueError
IndexError single positional indexer is out-of-bounds
2. TableModel.parse(region=tuple / pd.Index) -> misleading errors
tuple -> ValueError `adata.obs[region]` values do not match with `region` values.
Index -> TypeError unhashable type: 'Index'
3. RasterSchema.parse(chunks=<float>) -> ValueError from a wrong comprehension
ValueError not enough values to unpack (expected 2, got 1)
4. RasterSchema.parse mutates a numpy-backed input DataArray in place
input .data type after parse: Array
5. PointsModel.validate rejects pandas nullable / pyarrow numeric coordinate dtypes
Int64 -> ValueError Column `x` must be of type `int` or `float`.
float64[pyarrow] -> ValueError Column `x` must be of type `int` or `float`.
6. get_element_instances(shapes, return_background=True) -> TypeError (overload lacks the keyword)
TypeError _() got an unexpected keyword argument 'return_background'
7. set_table_annotates_spatialelement(region=pd.Series) stores the Series in uns -> validate fails
validate -> TypeError unhashable type: 'Series'
8. filter_by_table_query(element_names=[...]) -> KeyError when no table row annotates those elements
-> KeyError 't'
VERDICT: BUG REPRODUCED
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). Also reproduced in a second environment with pandas 2.3.3 / anndata 0.12.11 / numpy 2.4.4 / zarr 3.2.1.
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 the
spatialdatacode 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
Each item was confirmed with a script; the repro below demonstrates items 1–8.
GeoDataFrame→IndexErrorinShapesModel.parseandget_axes_names(.iloc[0]) instead of theValueError("Column geometry is empty")thatvalidatewould raise.TableModel.parse(region=("a", "b"))(tuple) fails with the misleadingadata.obs[region] values do not match with region values;region=pd.Index([...])fails withTypeError: unhashable type: 'Index'. Onlylist/np.ndarrayare normalised.RasterSchema.parse(chunks=<float>)crashes withValueError: not enough values to unpack({dim: chunks for index, dim in data.dims}iterates dimension names).RasterSchema.parse(DataArray)mutates its input: a numpy-backedDataArrayhas its.datareplaced by a dask array in place.PointsModel.validaterejects pandas nullable / pyarrow numeric coordinate dtypes (Int64,float64[pyarrow]) while accepting every numpy int/float — usepd.api.types.is_numeric_dtype.get_element_instances(shapes_or_points, return_background=True)→TypeError: _() got an unexpected keyword argument(the GeoDataFrame/DaskDataFrame overloads lack the keyword the generic signature advertises).set_table_annotates_spatialelement(region=pd.Series([...]))— the type hint allows a Series, but the Series object is stored inuns["spatialdata_attrs"]["region"];TableModel.validatethen fails withunhashable type: 'Series'and the table cannot be written.filter_by_table_query(table_name, element_names=[...])raisesKeyError: 't'when no table row annotates the requested elements (subset(filter_tables=True)drops the empty table beforesdata_subset.tables[table_name]).Not in the script:
python -m spatialdata peek <store> tablesilently drops the tables — the clickChoiceoffers"table"(singular) butread_zarrexpects"tables", andtablesis rejected by click.TableModel.parseuniqueness check computesgroupby(region).nunique()over all obs columns instead of only the instance key (10–100× slower; 0.35 s vs 0.02 s for 1 M rows × 54 columns). Usegrouped[instance_key].nunique().relabel_sequentialbreaks when the internal lookup array spans several dask chunks (max_label> ~16 M with the default chunk size):ValueError: Dimension 1 has N blocks, adjust_chunks specified with 1 blocks.rechunk(-1)the lookup array.polygon_query(circles, clip=True)returns Polygon geometries but keeps theradiuscolumn.to_polygons(circles)buffers row-by-row withDataFrame.apply(axis=1)(2.1 s for 167 k Xenium circles) whereasshapely.buffer(geoms, radii, quad_segs=...)takes 0.58 s with identical areas.map_rasterdocstring: changing dimensionality needsdrop_axis/new_axis(forwarded via**kwargs) in addition todims; with onlydims=("y", "x")the call fails with number of dimensions of the output data (3) differs....get_transformation_between_landmarksdocstring example usesPointsModel(points_moving)instead ofPointsModel.parse(...);_get_current_output_axescontains a dead statementset(transformation.map_axis.keys())._validate_compressor_argsmessages say 'between 1 and 9' in two places and 'between 0 and 9' in another; level 0 is accepted.rasterize_binsdocumentsreturn_regions_as_labels(parameter:return_region_as_labels);SpatialData.subsetdocumentsfilter_table(parameter:filter_tables);validate_axesdocumentsaxis(parameter:axes);get_extent's generic docstring lists its parameters under 'Returns';get_transformation_between_coordinate_systemsdoes not documentsdata/intermediate_coordinate_systems; the points↔geopandas converters do not documentsuppress_z_warning.Pandas4Warning: The copy keyword is deprecatedfromtable.obs.rename(columns=..., copy=False)inconcatenate._concatenate_tables(will raise in pandas 4).ShapesModel.validateinspects only the first geometry, so[Polygon, Point]without a radius column is accepted;validate_shapes_not_mixed_typesexists but is opt-in.da.uniqueon full-resolution labels insubset(),filter_by_coordinate_system()and spatial queries (0.1 s per 3648×5472 labels, 1.8 s forfilter_by_coordinate_systemon the 30-labels CosMx dataset); forfilter_by_coordinate_systema name-based filter would be O(n_rows). (See also Bounding box query APIs slowed down by join operations #1177.)Severity (agent's assessment): low (each item)
Where: various, see list
Reproduction
Save as
repro.pyand runuv run repro.py(the PEP 723 header pinsspatialdatato the commit the bug was found on; replace the URL fragment with@mainto test the current main branch).Observed output
Environment
uv run repro.pywith the PEP 723 metadata in the script (fresh, isolated environment;spatialdatabuilt frommain@ 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). Also reproduced in a second environment with pandas 2.3.3 / anndata 0.12.11 / numpy 2.4.4 / zarr 3.2.1.Possibly related issues
#1177
Automatically generated; discovered by an AI agent (Claude) and not yet reviewed by a human.