quickwit-oss/tantivy · error

Failed to acquire read lock on SegmentManager.

Error message

Failed to acquire read lock on SegmentManager.

What it means

SegmentManager::read (src/indexer/segment_manager.rs:107) unwraps a RwLock read guard on the segment registers and panics with this message if the lock is poisoned. The comment above it states the lock is acquired and released only inside SegmentManager and its operations are designed not to panic, so poisoning indicates an internal invariant violation — usually following another panic during segment operations (commit, merge, garbage collection).

Source

Thrown at src/indexer/segment_manager.rs:107

                .uncommitted
                .get_mergeable_segments(in_merge_segment_ids),
        )
    }
    /// Returns all of the segment entries (committed or uncommitted)
    pub fn segment_entries(&self) -> Vec<SegmentEntry> {
        let registers_lock = self.read();
        let mut segment_entries = registers_lock.uncommitted.segment_entries();
        segment_entries.extend(registers_lock.committed.segment_entries());
        segment_entries
    }

    // Lock poisoning should never happen :
    // The lock is acquired and released within this class,
    // and the operations cannot panic.
    fn read(&self) -> RwLockReadGuard<'_, SegmentRegisters> {
        self.registers
            .read()
            .expect("Failed to acquire read lock on SegmentManager.")
    }

    fn write(&self) -> RwLockWriteGuard<'_, SegmentRegisters> {
        self.registers
            .write()
            .expect("Failed to acquire write lock on SegmentManager.")
    }

    /// Deletes all empty segments
    fn remove_empty_segments(&self) {
        let mut registers_lock = self.write();
        registers_lock
            .committed
            .segment_entries()
            .iter()
            .filter(|segment| segment.meta().num_docs() == 0)
            .for_each(|segment| {
                registers_lock

View on GitHub (pinned to b5d8deb80c)

Solutions

  1. Fix the root-cause panic that happened while the write lock was held; the first panic in your logs is the real error.
  2. After a panic, discard the Index and reopen it from disk rather than continuing with the poisoned SegmentManager.
  3. Wrap indexing/commit code so a panic tears down the whole writer+reader set, not just one thread.
  4. Check custom DocMapping/segment-merge callbacks for panics and convert those error paths to Result instead.
  5. Report to tantivy if reproducible without an application-side panic.

Example fix

// before: keep using reader after worker panic
std::panic::catch_unwind(|| writer.commit()).ok();
let segs = reader.searcher().segment_readers(); // may hit poisoned lock

// after: reopen on panic
if std::panic::catch_unwind(|| writer.commit()).is_err() {
    (writer, reader) = Index::open_in_dir(&dir)?; // fresh SegmentManager
}
Defensive patterns

Strategy: try-catch

Try / catch

match std::panic::catch_unwind(AssertUnwindSafe(|| writer.commit())) {
    Ok(r) => r?,
    Err(_) => { (writer, reader) = reopen_index()?; }
}

Prevention

When it happens

Trigger: Any read-path call — fmt/debug printing, get_mergeable_segments, segment_entries, start_merge, committed_segment_metas — after a thread panicked while holding the SegmentManager write lock (e.g. during commit, add_segment or end_merge).

Common situations: An indexing/commit thread panics (e.g. on a schema mismatch or corrupted segment) while other reader threads continue using the same IndexReader/writer; long-lived services that swallow panics in worker threads; bugs in custom DocMappers or custom scorers that panic during commit.

Related errors


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