quickwit-oss/tantivy · error
Failed to acquire write lock on delete queue writer
Error message
Failed to acquire write lock on delete queue writer
What it means
DeleteQueue::push acquires a write lock on the queue's inner state to append a delete operation. The expect() panics if that RwLock was poisoned by a panic in another thread (e.g. a writer thread that crashed while mutating the queue).
Source
Thrown at src/indexer/delete_queue.rs:77
/// Creates a new cursor that makes it possible to
/// consume future delete operations.
///
/// Past delete operations are not accessible.
pub fn cursor(&self) -> DeleteCursor {
let last_block = self.get_last_block();
let operations_len = last_block.operations.len();
DeleteCursor {
block: last_block,
pos: operations_len,
}
}
/// Appends a new delete operations.
pub fn push(&self, delete_operation: DeleteOperation) {
self.inner
.write()
.expect("Failed to acquire write lock on delete queue writer")
.writer
.push(delete_operation);
}
// DeleteQueue is a linked list of blocks of
// delete operations.
//
// Writing happens by simply appending to a vec.
// `.flush()` takes this pending delete operations vec
// creates a new read-only block from it,
// and appends it to the linked list.
//
// `.flush()` happens when, for instance,
// a consumer reaches the last read-only operations.
// It then ask the delete queue if there happen to
// be some unflushed operations.
//
fn flush(&self) -> Option<Arc<Block>> {View on GitHub (pinned to b5d8deb80c)
Solutions
- Find the original panic that poisoned the delete queue lock in the logs and fix it.
- Discard the current IndexWriter and create a new one (the queue state is indeterminate).
- Avoid panicking inside threads that touch the IndexWriter; propagate errors instead.
- Serialize delete operations behind a higher-level mutex if you mix delete and commit paths in custom code.
Example fix
// before: continuing to use the writer after a panic writer.delete_term(term); // panics: poisoned queue // after let mut writer = index.writer(mem); // recreate writer writer.delete_term(term);
Defensive patterns
Strategy: try-catch
Validate before calling
null
Type guard
null
Try / catch
let res = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| writer.delete_term(term)));
if res.is_err() {
writer = index.writer(heap_size)?; // recreate: queue is poisoned
} Prevention
- Don't continue using an IndexWriter after any panic in its threads
- Validate terms/documents before issuing deletes
- Propagate errors instead of panicking in indexing code
- Wrap worker threads in catch_unwind and recreate the writer on failure
When it happens
Trigger: Calling index_writer.delete_term(...) or any delete-operation push while another thread panicked while holding the delete queue write lock (most commonly inside flush or a concurrent push).
Common situations: Mixed usage where a prior commit/rollback panicked and the user keeps issuing deletes on the same IndexWriter; long-running services swallowing panics in worker threads.
Related errors
- Empty DocOpstamp is forbidden
- Mmap cache lock is poisoned.
- Lock poisoned. This should never happen
- Field reader cache lock poisoned. This should never happen.
- Failed to acquire write lock in delete queue
AI-assisted analysis of quickwit-oss/tantivy@b5d8deb80c (2026-09-05).
Data as JSON: /api/errors/61e399328a7741f3.
Report an issue: GitHub.