tursodatabase/turso · error · Exception
jsContextPointer == 0
Error message
jsContextPointer == 0
What it means
TursoBridge.install() attaches the native sync engine to the React Native JS runtime by passing the runtime's raw JSI context pointer into installNativeJsi(). It throws this bare Exception when context.getJavaScriptContextHolder().get() returns 0, meaning the bridge saw no live JavaScriptCore/JSI runtime to install into. Without a valid pointer the native side cannot be initialized, so the library refuses rather than crashing the process later.
Solutions
- Trigger install only after the JS runtime exists: call it from JS through a native-module method invoked at app entry, or from onCatalystInstanceInitialized(), never from the module constructor.
- If you are on Expo, switch to a development build (expo run:android) - Expo Go cannot host custom JSI natives.
- After upgrading the turso/sync packages, do a full clean rebuild (cd android && ./gradlew clean, then rebuild) so native and JS sides match.
- On the New Architecture, load the module through the TurboModule/interop layer for your RN version and update to a bridge version that supports bridgeless mode.
Example fix
// before
public TurboTursoModule(ReactApplicationContext ctx) {
bridge.install(ctx); // JS runtime not live yet -> jsContextPointer == 0
}
// after: install lazily, the first time JS asks for it
private boolean installed = false;
@ReactMethod
public void install() throws Exception {
if (installed) return;
bridge.install(getReactApplicationContext()); // runtime is live now
installed = true;
} Defensive patterns
Strategy: validation
Validate before calling
ReactContext ctx = ...;
JavaScriptContextHolder holder = ctx.getJavaScriptContextHolder();
if (holder == null || holder.get() == 0) {
// JS runtime not up yet: wait for onCatalystInstanceInitialized / a JS-side signal
return;
}
bridge.install(ctx); Try / catch
try {
bridge.install(reactContext);
} catch (Exception e) {
Log.w("TursoBridge", "JSI install deferred: " + e.getMessage());
// schedule one retry once the runtime signals readiness; do not loop blindly
} Prevention
- Never install from the module constructor or process startup; wait until the JS runtime is live.
- Gate install behind an 'installed' flag so retries after readiness are no-ops.
- Do not use Expo Go for JSI-based natives; use development builds.
- Clean-rebuild the Android app after upgrading turso native packages.
When it happens
Trigger: Calling install(reactContext) before the Catalyst instance / JS runtime is up (e.g., in the module constructor or too early in onHostResume); running under a runtime that exposes no JS context (Expo Go, remote JS debugger, or an RN build without JSI support); calling install after invalidate() tore the runtime down.
Common situations: Enabling React Native's New Architecture / bridgeless mode where getJavaScriptContextHolder() is empty; using Expo Go, which forbids custom JSI native modules; upgrading the turso npm package without rebuilding the Android app so the native library and JS runtime mismatch; calling install from a background thread before onCatalystInstanceInitialized.
Related errors
- Turso native module not loaded
- @tursodatabase/sync-react-native: JSI bindings not found on…
- Database not connected. Call connect() first.
- @tursodatabase/sync-react-native: Failed to install JSI…
- @tursodatabase/sync-react-native: Native module not found…
AI-assisted analysis of tursodatabase/turso@244cde92a7 (2026-08-20).
Data as JSON: /api/errors/15cf1d92e1444c22.
Report an issue: GitHub.
Appendix: source
Thrown at bindings/react-native/android/src/main/java/com/turso/sync/reactnative/TursoBridge.java:29
public static TursoBridge getInstance() {
return instance;
}
private TursoBridge() {
}
private native void installNativeJsi(
long jsContextNativePointer,
CallInvokerHolderImpl jsCallInvokerHolder,
String dbPath);
private native void clearStateNativeJsi();
public void install(ReactContext context) throws Exception {
long jsContextPointer = context.getJavaScriptContextHolder().get();
if (jsContextPointer == 0) {
throw new Exception("jsContextPointer == 0");
}
CallInvokerHolderImpl jsCallInvokerHolder = (CallInvokerHolderImpl) context.getCatalystInstance()
.getJSCallInvokerHolder();
// getDatabasePath(...) returns file path - so we pass dummy value and remove it
// after to get directory path
String dbPath = context.getDatabasePath("tursoDatabaseFile").getAbsolutePath().replace("tursoDatabaseFile", "");
installNativeJsi(jsContextPointer, jsCallInvokerHolder, dbPath);
}
public void invalidate() {
clearStateNativeJsi();
}
}View on GitHub (pinned to 244cde92a7)