quickwit-oss/tantivy · error
Lock poisoned. This should never happen
Error message
Lock poisoned. This should never happen
What it means
SegmentReader::inverted_index reads from an internal RwLock-cached map of InvertedIndexReaders. The expect() fires when the lock is poisoned because another thread panicked while holding it. Tantivy treats this as unreachable in a healthy process, so it panics rather than returning an error.
Source
Thrown at src/index/segment_reader.rs:228
}
/// Returns a field reader associated with the field given in argument.
/// If the field was not present in the index during indexing time,
/// the InvertedIndexReader is empty.
///
/// The field reader is in charge of iterating through the
/// term dictionary associated with a specific field,
/// and opening the posting list associated with any term.
///
/// If the field is not marked as index, a warning is logged and an empty `InvertedIndexReader`
/// is returned.
/// Similarly, if the field is marked as indexed but no term has been indexed for the given
/// index, an empty `InvertedIndexReader` is returned (but no warning is logged).
pub fn inverted_index(&self, field: Field) -> crate::Result<Arc<InvertedIndexReader>> {
if let Some(inv_idx_reader) = self
.inv_idx_reader_cache
.read()
.expect("Lock poisoned. This should never happen")
.get(&field)
{
return Ok(Arc::clone(inv_idx_reader));
}
let field_entry = self.schema.get_field_entry(field);
let field_type = field_entry.field_type();
let record_option_opt = field_type.get_index_record_option();
if record_option_opt.is_none() {
warn!("Field {:?} does not seem indexed.", field_entry.name());
}
let postings_file_opt = self.postings_composite.open_read(field);
if postings_file_opt.is_none() || record_option_opt.is_none() {
// no documents in the segment contained this field.
// As a result, no data is associated with the inverted index.
//View on GitHub (pinned to b5d8deb80c)
Solutions
- Locate the original panic in the logs that poisoned the lock and fix that root cause (usually corrupted segment or IO error).
- Recreate the SegmentReader/Searcher after a panic instead of reusing it.
- Validate index files (e.g. re-open or re-index the segment) to eliminate the source of the inner panic.
- Avoid panicking inside custom query/scorer code that runs while holding segment reader locks.
Example fix
// before: reusing searcher after a worker thread panicked let inv = segment_reader.inverted_index(field)?; // panics: poisoned // after: rebuild searcher let searcher = reader.searcher(); let inv = searcher.segment_reader(seg_ord).inverted_index(field)?;
Defensive patterns
Strategy: try-catch
Validate before calling
// validate segment files exist before searching
for seg in searchable_segments {
for ext in ["idx", "store", "pos"] {
if let Some(f) = seg.meta().list_files().iter().find(|f| f.ends_with(ext)) {
std::fs::metadata(dir.join(f))?;
}
}
} Type guard
fn segment_readable(seg: &Segment) -> bool {
seg.meta().list_files().iter().all(|f| std::fs::metadata(f).is_ok())
} Try / catch
let res = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
searcher.search(&query, &collector)
}));
match res {
Ok(r) => r,
Err(_) => { reader.reload()?; searcher = reader.searcher(); retry_search()? }
} Prevention
- Validate index integrity before concurrent searching
- Never panic inside custom scorers or query impls
- Reload/reopen the reader after a panic instead of reusing it
- Catch panics at worker-thread boundaries
When it happens
Trigger: Any call to segment_reader.inverted_index(field) (directly or via scorer/phrase_scorer/fields_metadata/get_match_term_infos) while another thread panicked holding the inv_idx_reader_cache lock.
Common situations: A query execution thread panics (e.g. corrupt or truncated segment files, IO failure during index open) while holding the cache read lock; subsequent searches then panic with this message, masking the root cause.
Related errors
- Field reader cache lock poisoned. This should never happen.
- Mmap cache lock is poisoned.
- Failed to acquire write lock in delete queue
- Failed to acquire write lock on delete queue writer
- This lock should never be poisoned
AI-assisted analysis of quickwit-oss/tantivy@b5d8deb80c (2026-09-05).
Data as JSON: /api/errors/6535de426e8d1c26.
Report an issue: GitHub.