quickwit-oss/tantivy · error
FastFieldsPlugin is a built-in; use FastFieldsPluginWriter::
Error message
FastFieldsPlugin is a built-in; use FastFieldsPluginWriter::new
What it means
FastFieldsPlugin implements SegmentPlugin, but it is a built-in whose fast-field files are written by the segment writer itself. Its SegmentPlugin::create_writer deliberately panics with unimplemented!(); callers must construct FastFieldsPluginWriter directly instead of asking the plugin to create a writer.
Source
Thrown at src/fastfield/plugin.rs:34
use crate::fastfield::{FastFieldReaders, FastFieldsWriter};
use crate::index::{SegmentComponent, SegmentReader};
use crate::indexer::doc_id_mapping::{DocIdMapping, MappingType, SegmentDocIdMapping};
use crate::plugin::{PluginMergeContext, PluginWriter, PluginWriterContext, SegmentPlugin};
use crate::schema::document::Document;
use crate::schema::{value_type_to_column_type, Schema};
use crate::space_usage::{ComponentSpaceUsage, FAST_FIELDS};
use crate::Segment;
/// Built-in segment plugin that stores and merges fast-field columns.
pub struct FastFieldsPlugin;
impl SegmentPlugin for FastFieldsPlugin {
fn extensions(&self) -> &[&str] {
&["fast"]
}
fn create_writer(&self, _ctx: &PluginWriterContext) -> crate::Result<Box<dyn PluginWriter>> {
unimplemented!("FastFieldsPlugin is a built-in; use FastFieldsPluginWriter::new")
}
fn merge(&self, ctx: PluginMergeContext) -> crate::Result<()> {
debug_time!("write-fast-fields");
let path = ctx
.target_segment
.relative_path(SegmentComponent::FastFields);
let mut fast_field_wrt: WritePtr =
ctx.target_segment.index().directory().open_write(&path)?;
let required_columns = extract_fast_field_required_columns(ctx.schema);
let columnars: Vec<&ColumnarReader> = ctx
.readers
.iter()
.map(|reader| reader.fast_fields().columnar())
.collect();
// Clone the doc_id_mapping since convert_to_merge_order consumes it by valueView on GitHub (pinned to b5d8deb80c)
Solutions
- Use FastFieldsPluginWriter::new directly to create the fast-field writer
- Exclude FastFieldsPlugin from generic create_writer dispatch; special-case it (fast fields are handled internally during segment writing)
- Remove the plugin from any list of plugins expected to provide writers
Example fix
// before let writer = fast_fields_plugin.create_writer(ctx)?; // after let writer = FastFieldsPluginWriter::new(/* ... */);
Defensive patterns
Strategy: type-guard
Validate before calling
// only call create_writer on non-builtin plugins
if std::any::type_name::<P>() != "tantivy::fastfield::plugin::FastFieldsPlugin" {
let writer = plugin.create_writer(ctx)?;
} Type guard
fn builtin_fast_fields_plugin(p: &dyn SegmentPlugin) -> bool {
p.extensions() == &["fast"] && std::any::type_name_of_val(p).contains("FastFieldsPlugin")
} Try / catch
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| plugin.create_writer(ctx)));
match result {
Ok(w) => use_writer(w),
Err(_) => eprintln!("builtin plugin: use FastFieldsPluginWriter::new instead"),
} Prevention
- Never call create_writer on FastFieldsPlugin; construct FastFieldsPluginWriter::new
- Special-case built-in plugins in generic plugin pipelines
- Read SegmentPlugin docs to see which hooks are implemented per plugin
- Keep built-ins out of user-registered plugin lists
When it happens
Trigger: Calling FastFieldsPlugin.create_writer(ctx) — e.g. registering the plugin in a generic plugin pipeline that invokes create_writer for every plugin, or calling it manually.
Common situations: Misconfigured plugin registry treating the built-in plugin like an external one; custom segment-writer code iterating plugins and calling create_writer unconditionally.
Related errors
- At least one bound must be set
- expected json type in term
- unknown compressor id {id:?}
- actual doc store version: {doc_store_version}, max_supported
- Facet support in dynamic fields is not yet implemented
AI-assisted analysis of quickwit-oss/tantivy@b5d8deb80c (2026-09-05).
Data as JSON: /api/errors/1f88cd186e212b3d.
Report an issue: GitHub.