{"record":{"id":"398e3b53e316d901","repo":"docling-project/docling","slug":"cannot-specify-both-vlm-pipeline-preset-and-vlm-pi","errorCode":null,"errorMessage":"Cannot specify both vlm_pipeline_preset and vlm_pipeline_custom_config. Please use one or the other.","messagePattern":"Cannot specify both vlm_pipeline_preset and vlm_pipeline_custom_config\\. Please use one or the other\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"docling/datamodel/service/options.py","lineNumber":1008,"sourceCode":"            opt is not None\n            for opt in (\n                self.vlm_pipeline_model,\n                self.vlm_pipeline_model_local,\n                self.vlm_pipeline_model_api,\n            )\n        )\n        if num_not_nan > 1:\n            raise ValueError(\n                \"The parameters vlm_pipeline_model, vlm_pipeline_model_local and vlm_pipeline_model_api are mutually exclusive, only one of them can be set.\"\n            )\n\n        return self\n\n    @model_validator(mode=\"after\")\n    def validate_vlm_pipeline_options(self) -> Self:\n        \"\"\"Ensure preset and custom config are mutually exclusive for VLM pipeline.\"\"\"\n        if self.vlm_pipeline_preset and self.vlm_pipeline_custom_config:\n            raise ValueError(\n                \"Cannot specify both vlm_pipeline_preset and vlm_pipeline_custom_config. \"\n                \"Please use one or the other.\"\n            )\n\n        # Check if using legacy fields with new fields\n        legacy_set = (\n            self.vlm_pipeline_model is not None\n            or self.vlm_pipeline_model_local is not None\n            or self.vlm_pipeline_model_api is not None\n        )\n        new_set = (\n            self.vlm_pipeline_preset is not None\n            or self.vlm_pipeline_custom_config is not None\n        )\n\n        if legacy_set and new_set:\n            raise ValueError(\n                \"Cannot mix legacy VLM options (vlm_pipeline_model*) with new options \"","sourceCodeStart":990,"sourceCodeEnd":1026,"githubUrl":"https://github.com/docling-project/docling/blob/61d76f1ff3f8428065465889f7b4577da7df704c/docling/datamodel/service/options.py#L990-L1026","documentation":"Model validator on the service options: vlm_pipeline_preset (a named preset) and vlm_pipeline_custom_config (a full custom configuration) are the two new-style ways to configure the VLM pipeline and are mutually exclusive — a preset already fixes the config, so supplying both is contradictory.","triggerScenarios":"Request options containing both vlm_pipeline_preset='...' and vlm_pipeline_custom_config={...}, typically from a config template that fills a default preset while code adds a custom config for tuning.","commonSituations":"Teams sharing a base options JSON with a preset, then developers layering custom_config tweaks on top instead of forking the preset.","solutions":["Choose one: either the preset name or the fully custom config object.","If you need to tweak a preset, copy its contents into vlm_pipeline_custom_config, modify, and drop the preset field.","Strip default preset values from templates before adding custom configs."],"exampleFix":"# before\n{'vlm_pipeline_preset': 'vlm', 'vlm_pipeline_custom_config': {...}}  # ValueError\n\n# after\n{'vlm_pipeline_custom_config': {...}}","handlingStrategy":"validation","validationCode":"def vlm_preset_exclusive(o: dict) -> bool:\n    return not (o.get('vlm_pipeline_preset') and o.get('vlm_pipeline_custom_config'))","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Choose preset or custom_config, never both.","To tweak a preset, copy it into a custom_config and drop the preset key.","Keep base templates free of defaults that collide with per-request overrides."],"tags":["service","vlm","validation","mutual-exclusion"],"backgroundTag":null,"analyzedSha":"61d76f1ff3f8428065465889f7b4577da7df704c","analyzedAt":"2026-08-14T23:53:18.727Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}