{"record":{"id":"1cef2c6e16cb3e52","repo":"quickwit-oss/tantivy","slug":"field-reader-cache-lock-poisoned-this-should-neve","errorCode":null,"errorMessage":"Field reader cache lock poisoned. This should never happen.","messagePattern":"Field reader cache lock poisoned\\. This should never happen\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/index/segment_reader.rs","lineNumber":284,"sourceCode":"                \"Failed to open field {:?}'s positions in the composite file. Has the schema been \\\n                 modified?\",\n                field_entry.name()\n            );\n            DataCorruption::comment_only(error_msg)\n        })?;\n\n        let inv_idx_reader = Arc::new(InvertedIndexReader::new(\n            TermDictionary::open(termdict_file)?,\n            postings_file,\n            positions_file,\n            record_option,\n        )?);\n\n        // by releasing the lock in between, we may end up opening the inverting index\n        // twice, but this is fine.\n        self.inv_idx_reader_cache\n            .write()\n            .expect(\"Field reader cache lock poisoned. This should never happen.\")\n            .insert(field, Arc::clone(&inv_idx_reader));\n\n        Ok(inv_idx_reader)\n    }\n\n    /// Returns the list of fields that have been indexed in the segment.\n    /// The field list includes the field defined in the schema as well as the fields\n    /// that have been indexed as a part of a JSON field.\n    /// The returned field name is the full field name, including the name of the JSON field.\n    ///\n    /// The returned field names can be used in queries.\n    ///\n    /// Notice: If your data contains JSON fields this is **very expensive**, as it requires\n    /// browsing through the inverted index term dictionary and the columnar field dictionary.\n    ///\n    /// Disclaimer: Some fields may not be listed here. For instance, if the schema contains a json\n    /// field that is not indexed nor a fast field but is stored, it is possible for the field\n    /// to not be listed.","sourceCodeStart":266,"sourceCodeEnd":302,"githubUrl":"https://github.com/quickwit-oss/tantivy/blob/b5d8deb80c26924e6b007a5b1a7630f35ca64de4/src/index/segment_reader.rs#L266-L302","documentation":"This is the write side of the same inverted-index reader cache in SegmentReader: after a cache miss, the reader is inserted under a write lock whose poisoning triggers this panic. Like the read side, poisoning implies a thread panicked while holding the cache lock.","triggerScenarios":"First access to a field's inverted index on a segment triggers a write-lock insert while another thread has panicked holding that lock; reached via inverted_index(), scorer, phrase_scorer, fields_metadata, or get_match_term_infos.","commonSituations":"Concurrent searches where one thread panics inside InvertedIndexReader::open (corrupt store/idx files), then other threads panic here on cache insert.","solutions":["Fix the root panic that poisoned the lock (check earlier stack traces for InvertedIndexReader::open failures).","Repair or re-index the affected segment.","Recreate the SegmentReader/Searcher after the failure.","Reduce concurrency-induced panics by validating index integrity before searching."],"exampleFix":"// before\nlet inv = reader.inverted_index(field)?; // panics: cache lock poisoned\n// after: guard against root cause first\nlet inv = if segment_has_valid_index_files(seg) { reader.inverted_index(field)? } else { return Err(corrupt_segment_err) };","handlingStrategy":"try-catch","validationCode":"null","typeGuard":"null","tryCatchPattern":"let res = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {\n    segment_reader.inverted_index(field)\n}));\nif res.is_err() { searcher = rebuild_searcher(&reader)?; }","preventionTips":["Fix root causes of panics during InvertedIndexReader::open (corrupt files)","Re-index damaged segments promptly","Avoid sharing one SegmentReader across threads after failures","Run search workers with catch_unwind isolation"],"tags":["rust","panic","mutex-poisoning","concurrency","search"],"backgroundTag":"mutex-poisoned","analyzedSha":"b5d8deb80c26924e6b007a5b1a7630f35ca64de4","analyzedAt":"2026-09-05T13:20:51.521Z","contentChangedAt":"2026-09-05T13:20:51.521Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}