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

  1. Find the original panic that poisoned the delete queue lock in the logs and fix it.
  2. Discard the current IndexWriter and create a new one (the queue state is indeterminate).
  3. Avoid panicking inside threads that touch the IndexWriter; propagate errors instead.
  4. 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

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


AI-assisted analysis of quickwit-oss/tantivy@b5d8deb80c (2026-09-05). Data as JSON: /api/errors/61e399328a7741f3. Report an issue: GitHub.