fix: actionable error when API called before cloudsync_init#47
Merged
Conversation
Six functions produced misleading errors when called before any
cloudsync_init('<table_name>'):
cloudsync_changes -> "out of memory (7)"
cloudsync_db_version -> "Unable to retrieve db_version (not an error)"
cloudsync_db_version_next -> same pattern (SQLite) / silent -1 (PG)
cloudsync_set_filter -> 10+ "no such table" NOTICEs + generic trigger error
cloudsync_clear_filter -> same as set_filter
cloudsync_payload_apply -> 3x "no such table: cloudsync_settings" debug lines
followed by "Runtime error: not an error"
Add cloudsync_context_is_initialized() helper and guard each function
on its error branch. When the root cause is missing init, raise a
single message pointing at SELECT cloudsync_init('<table_name>').
The guard is a NULL-pointer check on the error branch only, so the
sync hot path (cloudsync_db_version_next stepped by merge triggers
on every received row) is unaffected.
cloudsync_changes on PostgreSQL was already graceful (empty result
set), so no fix was needed there.
Bumps to 1.0.17.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Asserts that every function guarded by the previous commit points the caller at cloudsync_init when called before any table has been set up for sync. Matches on the stable substring "cloudsync_init" rather than the full sentence, so future rewordings of the user-facing message do not break the test. Covers cloudsync_changes, cloudsync_db_version, cloudsync_db_version_next, cloudsync_set_filter, cloudsync_clear_filter, and cloudsync_payload_apply. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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
Six functions leaked low-level symptoms when called before any
cloudsync_init('<table_name>'). All six now raise a single actionable message pointing atSELECT cloudsync_init('<table_name>').Before / After
SELECT * FROM cloudsync_changes(SQLite)Error: out of memory (7)—SQLITE_NOMEMreturned by mistakeSELECT cloudsync_db_version()(SQLite)Unable to retrieve db_version (not an error).cloudsync is not initialized: call SELECT cloudsync_init('<table_name>') …SELECT cloudsync_db_version()(PG)Unable to retrieve db_version ()(empty parens)SELECT cloudsync_db_version_next()(SQLite)Unable to retrieve next_db_version (not an error).SELECT cloudsync_db_version_next()(PG)-1SELECT cloudsync_set_filter('foo', …)(SQLite / PG)"no such table"/NOTICE … does not exist, skippinglines followed by genericerror recreating triggerscloudsync_set_filter: table 'foo' is not configured for sync. Call SELECT cloudsync_init('foo') first.SELECT cloudsync_clear_filter('foo')(SQLite / PG)SELECT cloudsync_payload_apply(…)(SQLite / PG)"dbutils_settings_get_value error no such table: cloudsync_settings"thenRuntime error: not an errorcloudsync_changeson PostgreSQL was already graceful (empty result set) — no change needed.Implementation
cloudsync_context_is_initialized(data)— returnstruewhendata_version_stmtis prepared, which is only done bycloudsync_init(viacloudsync_add_dbvms→cloudsync_context_init).cloudsync_db_version_nextstepped by the merge triggers on every received row, andcloudsync_payload_applyon every inbound sync).cloudsync_payload_applythe guard is added once inside the sharedcloudsync_payload_apply()insrc/cloudsync.c, so all three callers (dbsync_payload_decode,dbsync_payload_load,and the PG SRF) inherit it.
Regression test
A new
do_test_uninit_error_messagesintest/unit.cinvokes each of the six functions on a fresh database (nocloudsync_initcalled) and asserts that every error message contains the stablesubstring
"cloudsync_init". Matching on a single token rather than full text keeps the test robust to future rewordings of the user-facing string.Test plan
make clean && make && make unittest— all OK (including the newUninit Error Messagestest)make postgres-docker-rebuild && make postgres-docker-run-test— 0 failures (port 5432, standalone)make postgres-supabase-rebuild && make postgres-supabase-run-test— 0 failures (port 54322, Supabase)cloudsync_init— unchangedVersion bumped to
1.0.17.