docling-project/docling · error · ValueError

Invalid JSON for nested config field: {exc}

Error message

Invalid JSON for nested config field: {exc}

What it means

Field validator (mode='before') on the docling service options: when a nested configuration field arrives as a string, it is parsed with json.loads; if parsing fails, this ValueError is raised with the underlying JSONDecodeError detail. It exists because multipart/form-data submissions (local-file conversions) must serialize nested configs as JSON strings, and malformed strings are caught here rather than deep inside Pydantic.

Source

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

        "table_structure_custom_config",
        "layout_custom_config",
        "picture_classification_custom_config",
        mode="before",
    )
    @classmethod
    def _decode_json_string_config(cls, value: Any) -> Any:
        """Accept a JSON-encoded string for nested config fields.

        Local-file conversions submit options as ``multipart/form-data``, where
        nested configs are sent as JSON strings because form fields cannot carry
        objects. Decode them back into dicts here. Values that already arrive as
        objects (e.g. via JSON request bodies) are returned unchanged.
        """
        if isinstance(value, str):
            try:
                return json.loads(value)
            except json.JSONDecodeError as exc:
                raise ValueError(
                    f"Invalid JSON for nested config field: {exc}"
                ) from exc
        return value

    # Field validators for deprecated fields - trigger warnings on assignment
    @field_validator("picture_description_api", mode="before")
    @classmethod
    def validate_picture_description_api(cls, v):
        """Emit deprecation warning when picture_description_api is set."""
        if v is not None:
            warnings.warn(
                "picture_description_api is deprecated. "
                "Please migrate to picture_description_preset or "
                "picture_description_custom_config.",
                DeprecationWarning,
                stacklevel=2,
            )
        return v

View on GitHub (pinned to 61d76f1ff3)

Solutions

  1. Ensure every nested config sent as a form field is serialized with json.dumps (never str(dict)).
  2. Validate the string with json.loads client-side before sending.
  3. Prefer the JSON request body endpoint when sending complex nested options.
  4. Check the exc detail in the message for the exact character position of the JSON syntax error.

Example fix

# before
requests.post(url, files=files, data={'pipeline_options': str(options_dict)})  # single quotes -> invalid JSON

# after
import json
requests.post(url, files=files, data={'pipeline_options': json.dumps(options_dict)})
Defensive patterns

Strategy: validation

Validate before calling

import json

def valid_nested_config_strings(payload: dict) -> bool:
    nested = ('pipeline_options',)  # keys your client sends as form strings
    return all(
        not isinstance(v, str) or _is_json(v)
        for k, v in payload.items() if k in nested
    )

def _is_json(s: str) -> bool:
    try:
        json.loads(s)
        return True
    except json.JSONDecodeError:
        return False

Try / catch

try:
    resp = requests.post(url, files=files, data=form)
except ValueError:
    # client-side: validate form strings with json.loads before sending
    pass

Prevention

When it happens

Trigger: POSTing to the service with multipart/form-data where a nested field (e.g., pipeline options or a nested config object) contains invalid JSON — missing quotes, trailing commas, single quotes, unescaped newlines. Does not fire for JSON request bodies, which arrive as real objects.

Common situations: Hand-built curl multipart forms; client code that str()-dumps a Python dict into a form field instead of json.dumps; form values truncated by proxies or shell quoting issues.

Understand the failure class

Related errors


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