{"record":{"id":"91091a8d23bb4515","repo":"quickwit-oss/tantivy","slug":"termmissingagg-collector-but-no-missing-found-in","errorCode":null,"errorMessage":"TermMissingAgg collector, but no missing found in agg req","messagePattern":"TermMissingAgg collector, but no missing found in agg req","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/aggregation/bucket/term_missing_agg.rs","lineNumber":94,"sourceCode":"            bucket_id_provider,\n        })\n    }\n}\n\nimpl SegmentAggregationCollector for TermMissingAgg {\n    fn add_intermediate_aggregation_result(\n        &mut self,\n        agg_data: &AggregationsSegmentCtx,\n        results: &mut IntermediateAggregationResults,\n        parent_bucket_id: BucketId,\n    ) -> crate::Result<()> {\n        self.prepare_max_bucket(parent_bucket_id, agg_data)?;\n        let req_data = agg_data.get_missing_term_req_data(self.accessor_idx);\n        let term_agg = &req_data.req;\n        let missing = term_agg\n            .missing\n            .as_ref()\n            .expect(\"TermMissingAgg collector, but no missing found in agg req\")\n            .clone();\n        let mut entries: FxHashMap<IntermediateKey, IntermediateTermBucketEntry> =\n            Default::default();\n\n        let missing_count = &self.missing_count_per_bucket[parent_bucket_id as usize];\n        let mut missing_entry = IntermediateTermBucketEntry {\n            doc_count: missing_count.missing_count as u64,\n            sub_aggregation: Default::default(),\n        };\n        if let Some(sub_agg) = &mut self.sub_agg {\n            let mut res = IntermediateAggregationResults::default();\n            sub_agg\n                .get_sub_agg_collector()\n                .add_intermediate_aggregation_result(agg_data, &mut res, missing_count.bucket_id)?;\n            missing_entry.sub_aggregation = res;\n        }\n        entries.insert(missing.into(), missing_entry);\n","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/quickwit-oss/tantivy/blob/b5d8deb80c26924e6b007a5b1a7630f35ca64de4/src/aggregation/bucket/term_missing_agg.rs#L76-L112","documentation":"A panic in `add_intermediate_aggregation_result` of TermMissingAgg: `agg_data.get_missing_term_req_data(...)` returned request data whose `.missing` field is `None`, but the collector only exists when a `missing` value was configured on the terms aggregation. This is an internal consistency violation between the aggregation request parsing and the collector construction — the intermediate result and the aggregation definition disagree.","triggerScenarios":"Calling `add_intermediate_aggregation_result` on a TermMissingAgg collector when the aggregation request carries `missing: None` — i.e. the request data was built without the `missing` parameter despite the missing-term collector being instantiated (typically a bug in request deserialization or collector wiring).","commonSituations":"A distributed search where intermediate aggregation results from one node/version are combined with request data built by another version; a bug in aggregation request parsing that drops the `missing` field; manually constructed intermediate agg results in tests/plugins.","solutions":["Check that every terms aggregation using the missing-term path actually sets a `missing` value in the request JSON.","Ensure all nodes in a cluster run the same engine version so request/intermediate formats match.","Inspect how the aggregation request is deserialized — a dropped `missing` field during parsing is the usual root cause.","If you maintain the code, return a descriptive internal error instead of expecting, to aid debugging."],"exampleFix":"// before\nlet missing = term_agg.missing.as_ref().expect(\"TermMissingAgg collector, but no missing found in agg req\").clone();\n// after\nlet missing = term_agg.missing.as_ref().cloned().ok_or_else(|| {\n    crate::AggregationError::Internal(\"TermMissingAgg without missing in req\".to_string())\n})?;","handlingStrategy":"validation","validationCode":"// Ensure the terms agg request actually sets \"missing\" when relying on the missing-term path.\nfn request_has_missing(req: &serde_json::Value) -> bool {\n    req.get(\"aggs\")\n        .and_then(|a| a.get(\"my_terms\"))\n        .and_then(|t| t.get(\"terms\"))\n        .map(|t| t.get(\"missing\").is_some())\n        .unwrap_or(false)\n}","typeGuard":null,"tryCatchPattern":"let res = std::panic::catch_unwind(|| finalize_intermediate_aggs(...));\nif res.is_err() {\n    log::error(\"agg finalization panic: missing-term collector without missing in request\");\n    return internal_error_response();\n}","preventionTips":["Always send the `missing` parameter when using a missing-term aggregation.","Run identical engine versions on every node so request parsing is consistent.","Do not hand-construct intermediate agg results; only use collector-produced ones."],"tags":["rust","panic","aggregation","internal-invariant","deserialization"],"backgroundTag":"internal-invariant-violation","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"}