tursodatabase/turso · error
subjournal must be opened
Error message
subjournal must be opened
What it means
Pager::try_use_subjournal() acquires statement-level ownership of the subjournal (the in-memory before-image store used for statement rollback). It expects the subjournal to have been created first via open_subjournal(); all in-engine call sites pair them as open_subjournal()? then try_use_subjournal()?. Calling try before a successful open panics with "subjournal must be opened".
Source
Thrown at core/storage/pager.rs:2198
.write_offset
.fetch_add(page_size as u64 + 4, Ordering::SeqCst);
})
};
let c = Completion::new_write(write_complete);
let subjournal = self.subjournal.read();
let subjournal = subjournal.as_ref().unwrap();
let c = subjournal.write_page(write_offset, page_size, buffer, c)?;
turso_assert!(c.succeeded(), "memory IO should complete immediately");
Ok(())
}
/// try to "acquire" ownership on the subjournal of the connection-scoped pager
/// if another statement owns the subjournal - return Busy error and let the caller retry attempt later
pub fn try_use_subjournal(&self) -> Result<()> {
let subjournal = self.subjournal.read();
let subjournal = subjournal.as_ref().expect("subjournal must be opened");
subjournal.try_use()
}
/// release ownership of the subjournal
/// caller must guarantee that [Self::stop_use_subjournal] is called only after successful call to the [Self::try_use_subjournal]
pub fn stop_use_subjournal(&self) {
let subjournal = self.subjournal.read();
let subjournal = subjournal.as_ref().expect("subjournal must be opened");
subjournal.stop_use()
}
/// check if subjournal is in use for some statement
pub fn subjournal_in_use(&self) -> bool {
let subjournal = self.subjournal.read();
let Some(subjournal) = subjournal.as_ref() else {
return false;
};
subjournal.in_use()View on GitHub (pinned to 492c4a71cd)
Solutions
- Call pager.open_subjournal()? immediately before pager.try_use_subjournal()?
- Never ignore the Result of open_subjournal - propagate errors before acquiring ownership
- In debug builds, assert the subjournal exists before acquiring
Example fix
// before pager.try_use_subjournal()?; // panics: subjournal was never opened // after pager.open_subjournal()?; pager.try_use_subjournal()?;
Defensive patterns
Strategy: validation
Validate before calling
// Acquire the subjournal in the documented order before use: pager.open_subjournal()?; // creates the in-memory subjournal pager.try_use_subjournal()?; // now safe: acquires statement ownership
Prevention
- Always call open_subjournal()? immediately before try_use_subjournal()? - mirror the VDBE call sites
- Propagate open_subjournal errors; never assume it succeeded implicitly
- Keep custom pager-driving code in sync with engine call-site patterns (vdbe/mod.rs, vdbe/execute.rs)
When it happens
Trigger: Code calling pager.try_use_subjournal() on a connection-scoped pager where open_subjournal() has not run, or where its Result was ignored and it failed before storing the Subjournal.
Common situations: Embedders driving the pager directly outside the VDBE flow, refactors that drop the open call on an error path, custom statement implementations.
Related errors
- in practice, clear_savepoints() should never fail as it uses
- clear_savepoints should not fail for attached DB
- buffer not loaded
- DB should not be initialized and should not do any IO
- Page size too small, a ptrmap page cannot map any db pages.
AI-assisted analysis of tursodatabase/turso@492c4a71cd (2026-08-20).
Data as JSON: /api/errors/f9670f54265fabe0.
Report an issue: GitHub.