Fail meaningfully on metadata a column cannot hold - #8518
Jens Hedegaard Nielsen (jenshnielsen) merged 4 commits into
Conversation
Adding metadata whose value is a nested dict or a sequence surfaced as a bare sqlite3 binding error wrapped in the generic rollback RuntimeError: sqlite3.ProgrammingError: Error binding parameter 1: type 'list' is not supported which names neither the tag nor what to do about it. validate_dynamic_column_data already rejects invalid tags and None with a clear message, so extend it to reject values SQLite cannot store. The check asks SQLite itself whether the value binds rather than comparing against a list of types, so values NumPy registers an adapter for -- scalars and arrays -- keep working as before. Fixes microsoft#1444 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #8518 +/- ##
=======================================
Coverage 71.99% 72.00%
=======================================
Files 305 305
Lines 32015 32025 +10
=======================================
+ Hits 23050 23060 +10
Misses 8965 8965 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Investigated both merge-queue removals. They are recorded as The queue fails during dependency installation: Evidence:
The PR does not change the dependency constraints. PyPI currently lists 0.11.3 as available and not yanked; I have not established why these runner installations cannot resolve it. Could the shared dependency-installation issue be checked before re-enqueuing? No code or workflow checks have been bypassed. Investigation prepared with Codex assistance. |
|
Shubham Padkonde (@Shubham-Padkonde) This is a pypi outage
|

Description
Adding metadata whose value is a nested dict or a sequence has failed with a raw sqlite3 binding error since #1444 was filed. On
mainatf6b9dd6:which names neither the offending tag nor what to do instead. Measured across value types:
{"b": 1}sqlite3.ProgrammingError: ... type 'dict' is not supported[1, 2]... type 'list' is not supported(1, 2)... type 'tuple' is not supported{1, 2}... type 'set' is not supportedIn the issue thread the ask was specifically to "fail in a meaningful way if you try to add nested fields as metadata", with the json-serialization workaround being the recommendation for the underlying use case. That is what this does — it does not try to pack/unpack sequences automatically.
validate_dynamic_column_dataalready rejects invalid tags andNonevalues with clear messages, so this extends it with the same shape of check. After:The error keeps the established house style: validation raises inside the transaction and the message reaches the caller through
__cause__, which is how the existing tag andNonechecks behave and whaterror_caused_byin the test suite reads.Why not a list of accepted types
QCoDeS registers sqlite3 adapters for NumPy types, so an allow-list would reject values that store correctly today. I checked what actually round-trips before the change:
np.int64(3)intnp.float64(2.5)floatnp.bool_(True)bytesnp.str_("s")strnp.array([1, 2])bytesSo the check asks SQLite itself whether the value binds, with a bare
SELECT ?against a throwaway in-memory connection. Anything with a registered adapter — including all of the above — is still accepted, and nothing is written anywhere by the probe. All five still store after the change.Related Issue(s)
Fixes #1444
Testing
Extended
test_metadataintests/dataset/test_dataset_basic.py, next to the existing bad-tag andNoneassertions, coveringdict,list,tupleandset, plus an assertion thatnp.int64metadata still round-trips.Without the change the new assertion fails:
With it:
ruff checkandruff format --checkare clean on both touched files.I could not run
mypyon the change: it exits with anINTERNAL ERRORinsidesrc/qcodes/dataset/data_set_protocol.pyon this machine (mypy 2.3.1). That reproduces on cleanmainwith my changes stashed, so it is not caused by this PR, but it does mean the type checking here has only been validated by CI rather than locally.Backwards-compatibility
A value that previously raised
sqlite3.ProgrammingErrornow raisesTypeError, both wrapped in the same rollbackRuntimeError. Nothing that stored successfully before is rejected now — that is what the NumPy table above is there to show.Code catching the inner
sqlite3.ProgrammingErrorspecifically would need to catchTypeErrorinstead, though that seems an unlikely thing to have depended on given the error was the bug being reported.Documentation
The docstring of
validate_dynamic_column_datanow lists what it raises and why. The surrounding docstrings already said "None is not a valid value"; the new sentence extends that to nested values.Disclosure: this change was written by Claude Code (Claude Opus 5) working as my agent, at my direction. The error messages and test output quoted above come from real runs in my local environment; I am accountable for the content of this PR and happy to iterate on review feedback.
🤖 Generated with Claude Code