{"record":{"id":"f4fbd897a6fc895d","repo":"squidfunk/mkdocs-material","slug":"expected-list-but-received-tags","errorCode":null,"errorMessage":"Expected list, but received: {tags}","messagePattern":"Expected list, but received: (.+?)","errorType":"validation","errorClass":"ValidationError","httpStatus":null,"severity":"error","filePath":"src/plugins/tags/structure/mapping/storage/__init__.py","lineNumber":161,"sourceCode":"def _mapping_from_json(data: object) -> Mapping:\n    \"\"\"\n    Return a mapping from a serialized representation.\n\n    Arguments:\n        data: Serialized representation.\n\n    Returns:\n        The mapping.\n    \"\"\"\n    if not isinstance(data, dict):\n        raise ValidationError(\n            f\"Expected dictionary, but received: {data}\"\n        )\n\n    # Ensure tags are iterable\n    tags = data.get(\"tags\")\n    if not isinstance(tags, list):\n        raise ValidationError(\n            f\"Expected list, but received: {tags}\"\n        )\n\n    # Ensure tags are valid\n    for tag in tags:\n        if not isinstance(tag, str):\n            raise ValidationError(\n                f\"Expected string, but received: {tag}\"\n            )\n\n    # Create and return mapping\n    return Mapping(\n        _mapping_item_from_json(data.get(\"item\")),\n        tags = [Tag(tag) for tag in tags]\n    )\n\ndef _mapping_item_from_json(data: object) -> Link:\n    \"\"\"","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/squidfunk/mkdocs-material/blob/e2136532f40aed98af1f6497c0cc6a3cff9f759b/src/plugins/tags/structure/mapping/storage/__init__.py#L143-L179","documentation":"Within a deserialized mapping, `_mapping_from_json` requires the `tags` field to be a list and then each tag to be a string; a non-list `tags` value (or, per the following loop, non-string elements) raises this ValidationError, ensuring tag data is uniformly typed.","triggerScenarios":"A mapping entry where `tags` is a string (`\"tag-a\"`), an object, or null instead of an array of strings; entries with numeric or nested-structure tag elements.","commonSituations":"Hand-authored exports using a single tag string; JSON produced by scripts that forgot to wrap a tag in a list; front matter styles where tags were a scalar and exported as-is.","solutions":["Change `tags` to an array of strings: `{\"tags\": [\"tag-a\"]}`.","Convert any single tag string into a one-element list.","Regenerate the mappings file with the plugin's export tooling to get canonical shapes.","Validate with a guard (`isinstance(tags, list) and all(isinstance(t, str) for t in tags)`) before loading."],"exampleFix":"// before\n{\"tags\": \"tag-a\"}\n\n// after\n{\"tags\": [\"tag-a\"]}","handlingStrategy":"type-guard","validationCode":"import json\ndata = json.load(open(path))\nfor i, entry in enumerate(data.get('mappings', [])):\n    tags = entry.get('tags')\n    assert isinstance(tags, list) and all(isinstance(t, str) for t in tags), f\"mappings[{i}].tags must be a list of strings\"","typeGuard":"def has_valid_tags(entry):\n    tags = entry.get('tags') if isinstance(entry, dict) else None\n    return isinstance(tags, list) and all(isinstance(t, str) for t in tags)","tryCatchPattern":"try:\n    yield from storage.load(path)\nexcept ValidationError as e:\n    log.error(f\"Invalid tags field in {path}: {e}\")\n    raise SystemExit(1)","preventionTips":["Always serialize tags as an array of strings, even for a single tag","Add a pre-export assertion that every tags value is a list[str]","Regenerate files with current tooling after version upgrades"],"tags":["json","validation","tags-plugin","mkdocs-material"],"backgroundTag":"schema-validation-failed","analyzedSha":"e2136532f40aed98af1f6497c0cc6a3cff9f759b","analyzedAt":"2026-08-29T11:20:04.299Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}