squidfunk/mkdocs-material · error · ValidationError

Expected dictionary, but received: {data}

Error message

Expected dictionary, but received: {data}

What it means

`Storage.load` reads a serialized tags mapping JSON file and requires the top-level JSON value to be an object (dictionary) containing `mappings`. If `json.load` produced anything else (list, string, number, null), it raises this ValidationError.

Source

Thrown at src/plugins/tags/structure/mapping/storage/__init__.py:95

            data = [_mapping_to_json(mapping) for mapping in mappings]
            json.dump(dict(mappings = data), f)

    def load(self, path: str) -> Iterable[Mapping]:
        """
        Load mappings from file.

        Arguments:
            path: The file path.

        Yields:
            The current mapping.
        """
        with open(path, "r", encoding = "utf-8") as f:
            data = json.load(f)

            # Ensure root dictionary
            if not isinstance(data, dict):
                raise ValidationError(
                    f"Expected dictionary, but received: {data}"
                )

            # Ensure mappings are iterable
            mappings = data.get("mappings")
            if not isinstance(mappings, list):
                raise ValidationError(
                    f"Expected list, but received: {mappings}"
                )

            # Create and yield mappings
            for mapping in mappings:
                yield _mapping_from_json(mapping)

# -----------------------------------------------------------------------------
# Functions
# -----------------------------------------------------------------------------

View on GitHub (pinned to e2136532f4)

Solutions

  1. Ensure the JSON root is an object: `{"mappings": [...]}` — wrap the array if needed.
  2. Re-export or regenerate the mappings file with the same mkdocs-material version rather than hand-editing it.
  3. Verify the file path passed to `load` actually points to a mappings file, not another JSON artifact.
  4. Add a pre-load check that the parsed JSON is a dict before calling `load`.

Example fix

// before
[
  {"tags": ["a"], ...}
]

// after
{
  "mappings": [
    {"tags": ["a"], ...}
  ]
}
Defensive patterns

Strategy: type-guard

Validate before calling

import json
with open(path) as f:
    data = json.load(f)
if not isinstance(data, dict):
    raise ValueError(f"{path}: mappings file root must be a JSON object")

Type guard

def is_mapping_file(data):
    return isinstance(data, dict) and isinstance(data.get('mappings'), list)

Try / catch

from mkdocs.structure.files import ValidationError
try:
    yield from storage.load(path)
except ValidationError as e:
    log.error(f"Corrupt mappings file {path}: {e}")
    raise SystemExit(1)

Prevention

When it happens

Trigger: Loading a tags cache/exports file whose root is a JSON array or scalar; a truncated or hand-edited mapping file; passing the wrong file (e.g. an array export) to `load`.

Common situations: Manually merging or editing exported tags JSON and dropping the outer object; older/newer export formats with a different root shape; accidentally pointing the loader at a different JSON file.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of squidfunk/mkdocs-material@e2136532f4 (2026-08-29). Data as JSON: /api/errors/8d69cbcc2ae1a27c. Report an issue: GitHub.