Skip to content

fix(sqlite-native): restore kv error hook#4635

Merged
NathanFlurry merged 1 commit intomainfrom
04-12-fix_sqlite-native_restore_kv_error_hook
Apr 24, 2026
Merged

fix(sqlite-native): restore kv error hook#4635
NathanFlurry merged 1 commit intomainfrom
04-12-fix_sqlite-native_restore_kv_error_hook

Conversation

@NathanFlurry
Copy link
Copy Markdown
Member

Description

Please include a summary of the changes and the related issue. Please also include relevant motivation and context.

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

Please describe the tests that you ran to verify your changes.

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

Copy link
Copy Markdown
Member Author

NathanFlurry commented Apr 13, 2026

This stack of pull requests is managed by Graphite. Learn more about stacking.

@claude
Copy link
Copy Markdown

claude Bot commented Apr 13, 2026

PR Review: fix(sqlite-native): restore kv error hook

Overview

Well-scoped and coherent bug fix. The core logic is sound: KV errors were being silently dropped at the VFS boundary, and this PR adds a proper channel to surface them from Rust to JavaScript with a useful, actionable error message. The implementation is generally correct.


Issues

wrapNativeStorageError is not annotated as @returns {never}

In wrapper.js, wrapNativeStorageError always throws unconditionally but is not typed or documented as such. At each call site, the code is slightly misleading - the exec path has an implicit undefined return after the catch block. At runtime this is fine (the function always throws), but it is a readability hazard. Consider annotating with JSDoc @returns {never} or restructuring so each call site ends with an explicit throw.

No tests for the new error-surfacing path

No new tests are added for:

  • xGetLastError VFS callback returning the correct message.
  • wrapNativeStorageError producing the enriched error with the KV error cause.
  • clear_last_error correctly resetting state on successful operations.

This is a behavior regression fix, so test coverage here would be especially valuable.

Pre-existing debug console.log statements in wrapper.js

There are several debug logs that appear to predate this PR but are still present and should be cleaned up.


Positive Notes

  • The last_error mutex accessor methods (clear_last_error, set_last_error, clone_last_error, take_last_error) are consistent and handle mutex-poisoned state with tracing::warn! rather than panicking, which is appropriate for code inside a VFS callback.
  • report_kv_error centralizes error handling cleanly: it sets the last error and calls on_error in one place.
  • clear_last_error on success correctly prevents stale errors from bleeding across queries.
  • Using clone_last_error in xGetLastError (non-consuming, SQLite may call multiple times) vs. take_last_error in the JS-facing path (consuming, JS reads once) is a thoughtful distinction.
  • The typeof nativeDb.takeLastKvError === "function" guard in wrapNativeStorageError is a good defensive check.
  • The config.notGlobal ?? false fix (from || false) is correct: false || false would have incorrectly coerced an explicit false through the || short-circuit.
  • The read_cache.as_ref().and_then(...) and value.as_deref() fixes are correct and appropriate.

Security Note

The error message written to the SQLite error buffer originates from the envoy KV error. If the envoy can return attacker-controlled strings in errors, those strings would be exposed to JavaScript callers via takeLastKvError(). Low risk given this is internal infrastructure, but worth being aware of.


Performance

The Mutex<Option<String>> for last_error adds negligible overhead per KV operation given the operations already cross async task boundaries via block_on.

@NathanFlurry NathanFlurry force-pushed the 04-12-perf_sqlite-native_avoid_cloning_cached_read_chunks branch from ceec0d4 to ff117f9 Compare April 13, 2026 05:38
@NathanFlurry NathanFlurry force-pushed the 04-12-fix_sqlite-native_restore_kv_error_hook branch from 6eac78f to 4e380c8 Compare April 13, 2026 05:38
@NathanFlurry NathanFlurry force-pushed the 04-12-perf_sqlite-native_avoid_cloning_cached_read_chunks branch from ff117f9 to e25c1b6 Compare April 13, 2026 05:50
@NathanFlurry NathanFlurry force-pushed the 04-12-fix_sqlite-native_restore_kv_error_hook branch 2 times, most recently from 7fbbf37 to fe8cf4f Compare April 13, 2026 07:03
@NathanFlurry NathanFlurry force-pushed the 04-12-perf_sqlite-native_avoid_cloning_cached_read_chunks branch from e25c1b6 to 532364f Compare April 13, 2026 07:03
@NathanFlurry NathanFlurry force-pushed the 04-12-perf_sqlite-native_avoid_cloning_cached_read_chunks branch from 591dff0 to badd4c3 Compare April 24, 2026 07:33
@NathanFlurry NathanFlurry force-pushed the 04-12-fix_sqlite-native_restore_kv_error_hook branch from 455165f to b488e7c Compare April 24, 2026 07:33
Base automatically changed from 04-12-perf_sqlite-native_avoid_cloning_cached_read_chunks to main April 24, 2026 07:38
@NathanFlurry NathanFlurry merged commit b488e7c into main Apr 24, 2026
12 of 49 checks passed
@NathanFlurry NathanFlurry deleted the 04-12-fix_sqlite-native_restore_kv_error_hook branch April 24, 2026 07:39
This was referenced Apr 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant