Squidpy · spatial_neighbors_delaunay · h5ad · IORegistryError · still in latest release
Squidpy's Delaunay Radius Pruning Builds a Graph You Can't Save — Here's the Workaround
Status as of writing: reproducible on Squidpy's latest stable release, v1.8.3 (2026-06-29). A fix merged to main via PR #1249 on 2026-08-11, but as of this writing that fix has not yet shipped in a release — if you installed from PyPI, you still hit this. Reported in squidpy#1247.
If you build a spatial graph with radius-pruned Delaunay triangulation and then try to save the object, the graph itself builds fine — the error only shows up later, at write_h5ad():
sq.gr.spatial_neighbors_delaunay(adata, radius=(0.0, 150.0))
# runs fine — graph is built, edges are pruned correctly
adata.write_h5ad("out.h5ad")
# IORegistryError: No method registered for writing
# into
# Error raised while writing key 'radius' of ... to /uns/spatial_neighbors/params
Why it only fails on save
The graph construction works because nothing about building the Delaunay graph needs to serialize anything. The tuple only becomes a problem when write_h5ad tries to write adata.uns to disk — adata.uns['spatial_neighbors']['params']['radius'] is stored as a native Python tuple, and anndata's h5ad writer has no registered encoder for a bare tuple inside an HDF5 group — only for types it explicitly knows how to serialize (lists, arrays, scalars, dicts of the same).
This is exactly the kind of failure that's easy to lose an afternoon to if you're new to the ecosystem: the traceback points at anndata's I/O registry deep in a stack of writer/wrapper functions, with no obvious link back to the one line that actually caused it (passing a tuple radius argument, dozens of lines earlier and a different function call entirely).
The workaround (works today, no waiting for the release)
Cast the stored value to a list before saving — anndata knows exactly how to serialize a list:
sq.gr.spatial_neighbors_delaunay(adata, radius=(0.0, 150.0))
# fix in place, before writing:
adata.uns['spatial_neighbors']['params']['radius'] = list(
adata.uns['spatial_neighbors']['params']['radius']
)
adata.write_h5ad("out.h5ad") # now succeeds
Alternatively, if you don't need the parameter recorded, del adata.uns['spatial_neighbors']['params']['radius'] before saving — but the list-cast is preferable since it keeps the record of what radius you actually used, which matters for reproducibility.
When the real fix lands
PR #1249 ("ensure radius values stored in AnnData.uns are writable") changes Squidpy's own storage code to cast to a writable type before it ever reaches adata.uns, so once it ships in a release you can drop the manual workaround above. Until then — or if you're pinned to an older version for other reasons — the one-line cast is a complete fix, not a partial one; it doesn't change your graph, only how the parameter gets serialized.
Verified against Squidpy's main branch, PR #1249, and the current v1.8.3 release, 2026-09. Source: squidpy#1247.