docling-project/docling · error · ValueError

Cannot specify both layout_preset and layout_custom_config.

Error message

Cannot specify both layout_preset and layout_custom_config.

What it means

A Pydantic model validator on the service conversion options rejects configurations that set both layout_preset and layout_custom_config. The layout stage accepts either a named preset or a fully custom configuration dictionary, never both. Validation happens at options construction time.

Source

Thrown at docling/datamodel/service/options.py:1080

        # when the fields are set, not here in the model validator

        return self

    @model_validator(mode="after")
    def validate_code_formula_options(self) -> Self:
        """Ensure preset and custom config are mutually exclusive for code/formula."""
        if self.code_formula_preset and self.code_formula_custom_config:
            raise ValueError(
                "Cannot specify both code_formula_preset and code_formula_custom_config."
            )

        return self

    @model_validator(mode="after")
    def validate_layout_options(self) -> Self:
        """Ensure preset and custom config are mutually exclusive for layout."""
        if self.layout_preset and self.layout_custom_config:
            raise ValueError(
                "Cannot specify both layout_preset and layout_custom_config."
            )
        return self

    @model_validator(mode="after")
    def validate_picture_classification_options(self) -> Self:
        """Ensure preset and custom config are mutually exclusive for picture classification."""
        if (
            self.picture_classification_preset
            and self.picture_classification_custom_config
        ):
            raise ValueError(
                "Cannot specify both picture_classification_preset and "
                "picture_classification_custom_config."
            )
        return self

    @model_validator(mode="after")

View on GitHub (pinned to 61d76f1ff3)

Solutions

  1. Remove one of the two keys: keep layout_preset for named presets or layout_custom_config for bespoke settings.
  2. If you used the custom config only to reproduce a preset, drop it and rely on the preset id.
  3. Add an assertion in your config loader that at most one of the pair is present before submitting.

Example fix

# before
opts = ConvertOptions(
    layout_preset="precise",
    layout_custom_config={"do smash": False},
)

# after
opts = ConvertOptions(
    layout_preset="precise",
)
Defensive patterns

Strategy: validation

Validate before calling

def assert_layout(opts: dict) -> None:
    assert not (opts.get("layout_preset") and opts.get("layout_custom_config")), (
        "layout_preset and layout_custom_config are mutually exclusive"
    )

Try / catch

try:
    ConvertOptions(**cfg)
except ValidationError as e:
    if "layout_preset" in str(e):
        raise ValueError("Config sets both layout preset and custom config; remove one") from e
    raise

Prevention

When it happens

Trigger: Passing both layout_preset and layout_custom_config in the options model, e.g. ConvertOptions(layout_preset='precise', layout_custom_config={'threshold': 0.4}). The validator validate_layout_options raises immediately after the model is built.

Common situations: Starting from a preset-based config and layering a custom layout dict on top; CI configs assembled from multiple YAML fragments that each contribute one of the two keys; upgrading docling versions where options were renamed from a single field into the preset/custom pair.

Related errors


AI-assisted analysis of docling-project/docling@61d76f1ff3 (2026-08-14). Data as JSON: /api/errors/4354c5cbd4f3a234. Report an issue: GitHub.