quickwit-oss/tantivy · error
The IndexWriter does not have any lock. This is a bug, pleas
Error message
The IndexWriter does not have any lock. This is a bug, please report.
What it means
IndexWriter holds a special directory lock handle that guarantees only one writer exists per index. rollback() takes this lock out of self to construct a replacement writer; if the field is already None the writer invariant is broken, so tantivy panics and asks for a bug report.
Source
Thrown at src/indexer/index_writer.rs:576
///
/// This cancels all of the updates that
/// happened after the last commit.
/// After calling rollback, the index is in the same
/// state as it was after the last commit.
///
/// The opstamp at the last commit is returned.
pub fn rollback(&mut self) -> crate::Result<Opstamp> {
debug!("Rolling back to opstamp {}", self.committed_opstamp);
// marks the segment updater as killed. From now on, all
// segment updates will be ignored.
self.segment_updater.kill();
let document_receiver_res = self.operation_receiver();
// take the directory lock to create a new index_writer.
let directory_lock = self
._directory_lock
.take()
.expect("The IndexWriter does not have any lock. This is a bug, please report.");
let new_index_writer =
IndexWriter::new(self.index.clone(), self.options.clone(), directory_lock)?;
// the current `self` is dropped right away because of this call.
//
// This will drop the document queue, and the thread
// should terminate.
*self = new_index_writer;
// Drains the document receiver pipeline :
// Workers don't need to index the pending documents.
//
// This will reach an end as the only document_sender
// was dropped with the index_writer.
if let Ok(document_receiver) = document_receiver_res {
for _ in document_receiver {}
}View on GitHub (pinned to b5d8deb80c)
Solutions
- Do not call rollback() twice on the same IndexWriter; after a rollback, only use the newly returned writer.
- Restructure cleanup code so rollback runs exactly once (use an Option/flag or a single exit path).
- Never share the IndexWriter across threads performing rollback concurrently — rollback requires &mut self / exclusive access.
- If hit in normal single-rollback usage, report it as a tantivy bug with a backtrace.
Example fix
// before writer.rollback()?; // cleanup path writer.rollback()?; // panics: lock already taken // after let mut writer = writer.rollback()?; // cleanup only via the new writer; rollback not repeated writer.commit()?;
Defensive patterns
Strategy: type-guard
Validate before calling
// track rollback usage in your own code
struct RollbackGuard { done: bool }
impl RollbackGuard {
fn can_rollback(&self) -> bool { !self.done }
} Type guard
fn can_rollback(w: &IndexWriter, already_rolled_back: &mut bool) -> bool {
if *already_rolled_back { return false; }
*already_rolled_back = true; // mark before calling
true
} Try / catch
null
Prevention
- Call rollback exactly once per IndexWriter; use the writer returned by rollback afterwards
- Never run rollback from two threads concurrently
- Structure error handling with a single cleanup path (guard/flag)
- After rollback, discard the old writer reference completely
When it happens
Trigger: Calling rollback() (or commit that internally uses the lock path) more than once after the _directory_lock has already been taken — e.g. calling rollback twice, or using the writer after a rollback replaced it.
Common situations: Error-handling code that calls rollback in a cleanup path after an earlier rollback/commit already consumed the lock; using a moved/dropped writer reference; concurrent rollback from two threads.
Related errors
- unknown compressor id {id:?}
- actual doc store version: {doc_store_version}, max_supported
- FastFieldsPlugin is a built-in; use FastFieldsPluginWriter::
- Exist query without a field isn't allowed
- All columns re required to be numerical
AI-assisted analysis of quickwit-oss/tantivy@b5d8deb80c (2026-09-05).
Data as JSON: /api/errors/8d291a489f2da284.
Report an issue: GitHub.