Clear empty strings left in nullable JSON columns at boot - #2103
Open
Abhishek-B-R wants to merge 1 commit into
Open
Abhishek-B-R wants to merge 1 commit into
Abhishek-B-R wants to merge 1 commit into
Conversation
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Databases carried forward from before the FumaDB cutover can hold
''instead of NULL in nullable JSON columns (the report has it inconnection.credential_write). The JSON row mapper callsJSON.parse, which throws on an empty string inside the row mapper, so the wholefindManyfails.connections.listruns on every toolkit MCP session, so everyPOST /mcp/toolkits/<slug>initializereturned 500.This adds a boot-time data migration, modelled on
bigintStorageClassSqliteMigration:jsonand nullable, nine today acrossconnection,integration,oauth_client,toolandartifact), so a column added later is covered without editing a list.''and sets them to NULL, which is what the ORM writes for "no value". It runs inside BEGIN/COMMIT and is idempotent.item_idsare left alone, since an empty string there has no faithful replacement.connection. Local is one step past the issue; it follows fix(local): repair bigint columns left in SQLite's integer storage class #1823, which registered in both, and is easy to drop if you want self-host only.The migration is named
2026-09-24-empty-json-columns, following the other date-prefixed names.On the second crash in the issue (
tools_synced_atholding a number): that is the shapebigintStorageClassSqliteMigration(#1823) already repairs across every bigint column, and its test coversconnection.tools_synced_at, so there is no second migration here. The suggestedtypeof(tools_synced_at) = 'blob'predicate would also clear healthy values, since BLOB is the current representation. If a number was written into that column after the bigint migration was stamped, that is a separate writer and probably worth its own issue.I did not treat
''as NULL insideSQLiteTextJson.mapFromDriverValue, since that changes the read path for every JSON column on every driver; a one-time data repair keeps the mapper strict.Linked issue
Closes #2092
Verification
sqlite-empty-json-migration.test.tsseeds legacy rows with raw SQL and checks that the read throws before the migration, that''becomes NULL while valid JSON and NULL are untouched, that a second run changes nothing, thatitem_idsis left alone, and that the column list matches every nullable JSON column the schema declares.legacy-empty-json-boot.test.tsinapps/host-selfhostseeds aconnectionrow with''incredential_write,last_healthandprovider_state, showsfindManythrowing, then runsselfHostDataMigrationsand reads the row back. It fails if the entry is removed from the registry.oxfmt --checkon the changed files: cleanoxlint -c .oxlintrc.jsonc --deny-warningsoverpackages/core/sdk,apps/host-selfhost,apps/local, andbun run lint:changelog-stubs: cleantsgo --noEmitinpackages/core/sdk,apps/host-selfhost,apps/local: exit 0vitest run:packages/core/sdk949 passed (65 files),apps/host-selfhost160 passed (27 files),apps/local(bunx --bun vitest run) 104 passed (17 files)e2e: not run; the boot test above covers the self-host registry path
Checklist
bun run changeset), or this change needs none.