Skip to content

fix: name offending elements when writing object arrays with non-strings to h5ad - #2667

Open
SajalDevX wants to merge 1 commit into
scverse:mainfrom
SajalDevX:fix/h5ad-object-array-error
Open

SajalDevX wants to merge 1 commit into
scverse:mainfrom
SajalDevX:fix/h5ad-object-array-error

Conversation

@SajalDevX

Copy link
Copy Markdown
  • Closes #
  • Tests added

What

Writing an object array that holds non-str items (None, nan, ints, …) as a string array to h5ad currently fails with h5py's bare

TypeError: Can't implicitly convert non-string objects to strings
Error raised while writing key 'k' of <class 'h5py._hl.group.Group'> to /uns

The key is reported (thanks to #1272), but not what inside the array is wrong, and the #726 thread shows how often people hit this without knowing which values to fix. With this PR the same case raises

TypeError: Cannot write object array as string array: 1 of 2 elements are not str (found types: NoneType), e.g. element (1,) is None. Convert the array to str before writing. For missing values, use a categorical or a nullable pandas string dtype instead of None/nan.
Error raised while writing key 'k' of <class 'h5py._hl.group.Group'> to /uns

chained (from) to h5py's original error.

How

write_vlen_string_array (h5py) wraps the create_dataset call in a try/except TypeError; on failure a small helper scans the object array for non-str items and raises the descriptive error. If the array is not an object array, or all items are str, the original exception is re-raised untouched. Nothing runs on the happy path, so there is no cost for valid arrays.

Reproducer:

import numpy as np, anndata as ad
a = ad.AnnData(X=np.zeros((2, 2), dtype=np.float32))
a.uns["k"] = np.array(["a", None], dtype=object)
a.write_h5ad("x.h5ad")

Note on zarr

write_vlen_string_array_zarr behaves differently: it silently coerces these items to strings (np.array(["a", 1], dtype=object) round-trips as ["a", "1"]). I left that alone and only skip the new test for zarr, but it may be worth making the two backends consistent — happy to follow up either way if you tell me which direction you prefer.

…ngs to h5ad

Writing an object array that holds anything other than str (None, nan,
numbers) as a string array to h5ad failed with h5py's bare
"Can't implicitly convert non-string objects to strings", which does not
say what the offending values are. Catch that TypeError in
write_vlen_string_array, find the non-str items and raise a TypeError
that gives their count, types and the position of the first one, chained
to the original error. The happy path is unchanged and there is no cost
unless h5py raises.

zarr is unaffected: it coerces such items to strings silently, which the
new test notes and skips.
@SajalDevX
SajalDevX force-pushed the fix/h5ad-object-array-error branch from e88ecb7 to 984d1ac Compare September 29, 2026 12:08
@codecov

codecov Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 82.35294% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.78%. Comparing base (c2c1c37) to head (984d1ac).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/anndata/_io/specs/methods.py 82.35% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2667      +/-   ##
==========================================
- Coverage   87.62%   85.78%   -1.85%     
==========================================
  Files          49       49              
  Lines        8129     8145      +16     
==========================================
- Hits         7123     6987     -136     
- Misses       1006     1158     +152     
Files with missing lines Coverage Δ
src/anndata/_io/specs/methods.py 91.38% <82.35%> (-0.61%) ⬇️

... and 7 files with indirect coverage changes

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant