{"record":{"id":"9f6e4beade56ab1f","repo":"quickwit-oss/quickwit","slug":"doc-mapper-must-be-present-if-there-are-delete-tas","errorCode":null,"errorMessage":"doc mapper must be present if there are delete tasks","messagePattern":"doc mapper must be present if there are delete tasks","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"quickwit/quickwit-indexing/src/actors/merge_executor.rs","lineNumber":547,"sourceCode":"        let mut directory_stack: Vec<Box<dyn Directory>> = vec![\n            output_directory.box_clone(),\n            Box::new(shadowing_meta_json_directory),\n        ];\n        directory_stack.extend(split_directories);\n        let union_directory = UnionDirectory::union_of(directory_stack);\n        let union_index = open_index(\n            union_directory,\n            self.doc_mapper.tokenizer_manager().tantivy_manager(),\n        )?;\n\n        ctx.record_progress();\n        let _protect_guard = ctx.protect_zone();\n\n        let mut index_writer: IndexWriter = union_index.writer_with_num_threads(1, 15_000_000)?;\n        let num_delete_tasks = delete_tasks.len();\n        if num_delete_tasks > 0 {\n            let doc_mapper = doc_mapper_opt\n                .ok_or_else(|| anyhow!(\"doc mapper must be present if there are delete tasks\"))?;\n            for delete_task in delete_tasks {\n                let delete_query = delete_task\n                    .delete_query\n                    .expect(\"A delete task must have a delete query.\");\n                let query_ast: QueryAst = serde_json::from_str(&delete_query.query_ast)\n                    .context(\"invalid query_ast json\")?;\n                // We ignore the docmapper default fields when we consider delete query.\n                // We reparse the query here defensively, but actually, it should already have been\n                // done in the delete task rest handler.\n                let parsed_query_ast = query_ast.parse_user_query(&[]).context(\"invalid query\")?;\n                debug!(\n                    \"Delete all documents matched by query `{:?}`\",\n                    parsed_query_ast\n                );\n                let (query, _) =\n                    doc_mapper.query(union_index.schema(), parsed_query_ast, false, None)?;\n                index_writer.delete_query(query)?;\n            }","sourceCodeStart":529,"sourceCodeEnd":565,"githubUrl":"https://github.com/quickwit-oss/quickwit/blob/a39730c5cdcd1a4fe798403737ae293999ea21f8/quickwit/quickwit-indexing/src/actors/merge_executor.rs#L529-L565","documentation":"When merging splits that also apply delete tasks, the merged index must be opened with the index's doc mapper so delete queries can be translated into tantivy delete operations. If delete tasks exist but `doc_mapper_opt` is `None`, this invariant is violated and the merge fails with this error.","triggerScenarios":"`merge_split_directories` is called from `process_merge` or `process_delete_and_merge` with a non-empty `delete_tasks` list while the merge plan/context carries no doc mapper (e.g. a merge-only path that never loaded the index doc mapping).","commonSituations":"Merges triggered on indexes whose doc mapping could not be loaded, delete tasks racing with an index config change, or internal code paths passing `None` for doc_mapper while deletes are pending.","solutions":["Ensure the doc mapper is loaded from the metastore and passed into the merge operation whenever delete tasks exist.","Check whether the index metadata/doc mapping is intact in the metastore.","Retry the merge after confirming the index config is valid; investigate the caller that supplied `None`.","If it recurs with valid metadata, report as a Quickwit bug."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if !delete_tasks.is_empty() && doc_mapper_opt.is_none() {\n    return Err(\"cannot run merge with delete tasks and no doc mapper\");\n}","typeGuard":null,"tryCatchPattern":"match result {\n    Err(e) if e.to_string().contains(\"doc mapper must be present\") => {\n        // reload index metadata and retry the merge\n    }\n    other => other?,\n}","preventionTips":["Always load the doc mapper when delete tasks may be pending.","Verify index metadata integrity in the metastore before merges.","Serialize delete-task application with merge scheduling."],"tags":["indexing","merge","delete-tasks","invariant"],"backgroundTag":"internal-invariant-violation","analyzedSha":"a39730c5cdcd1a4fe798403737ae293999ea21f8","analyzedAt":"2026-09-08T13:19:37.784Z","contentChangedAt":"2026-09-08T13:19:37.784Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}