{"record":{"id":"0fe566e4010b6342","repo":"apache/superset","slug":"errors-0fe566","errorCode":null,"errorMessage":"{errors}","messagePattern":"\\{errors\\}","errorType":"validation","errorClass":"ValidationError","httpStatus":422,"severity":"error","filePath":"superset/dashboards/schemas.py","lineNumber":128,"sourceCode":"\n\ndef validate_json(value: Union[bytes, bytearray, str]) -> None:\n    try:\n        json.validate_json(value)\n    except json.JSONDecodeError as ex:\n        raise ValidationError(\"JSON not valid\") from ex\n\n\ndef validate_json_metadata(value: Union[bytes, bytearray, str]) -> None:\n    if not value:\n        return\n    try:\n        value_obj = json.loads(value)\n    except json.JSONDecodeError as ex:\n        raise ValidationError(\"JSON not valid\") from ex\n    errors = DashboardJSONMetadataSchema().validate(value_obj, partial=False)\n    if errors:\n        raise ValidationError(errors)\n\n\n# Patterns for CSS constructs that can be abused to execute scripts or pull in\n# remote stylesheets/resources. The custom CSS is stored verbatim and re-served\n# into the dashboard page, so these are rejected at validation time. Ordinary\n# styling (including ``url(...)`` referencing relative paths or ``data:`` image\n# URIs) is left untouched.\n_CSS_SCRIPT_SCHEME = r\"(?:javascript|vbscript|livescript|mocha)\\s*:\"\n_DANGEROUS_CSS_PATTERNS: tuple[tuple[str, \"re.Pattern[str]\"], ...] = (\n    # Legacy IE dynamic expressions, e.g. ``width: expression(alert(1))``.\n    (\"expression(\", re.compile(r\"expression\\s*\\(\", re.IGNORECASE)),\n    # Inline script schemes anywhere in the declaration.\n    (\"script scheme\", re.compile(_CSS_SCRIPT_SCHEME, re.IGNORECASE)),\n    # Remote stylesheet imports.\n    (\"@import\", re.compile(r\"@import\\b\", re.IGNORECASE)),\n    # url(...) pointing at a script scheme. Legitimate image/relative/data URLs\n    # are intentionally not matched here.\n    (","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/apache/superset/blob/f4587218dd19d046c3e4d00063e7d27f8a2ed354/superset/dashboards/schemas.py#L110-L146","documentation":"After the metadata string parses as JSON, it is run through DashboardJSONMetadataSchema (marshmallow). Any field-level violations (wrong types for native_filter_configuration, chart_configuration, timed_refresh_immune_slices, etc.) produce an errors dict, which is raised verbatim as the ValidationError message. The {errors} message is therefore a map of field name to list of problems.","triggerScenarios":"PUT /api/v1/dashboard/ with syntactically valid metadata JSON whose values have the wrong shape: native_filter_configuration not a list of dicts, chart_configuration not a dict, timed_refresh_immune_slices containing non-integers, color_scheme not a string.","commonSituations":"Copying dashboard JSON between Superset versions whose filter/chart config schema changed; scripting dashboard updates and mutating metadata fields with wrong types; AI/generated dashboard configs.","solutions":["Read the errors dict — each key names the offending metadata field and the message says the expected type.","Align the value with DashboardJSONMetadataSchema (superset/dashboards/schemas.py): lists of dicts for filter/chart configs, lists of integers for timed_refresh_immune_slices, dict for chart_configuration.","Pull a known-good dashboard's metadata via the API and diff your payload against it field by field.","After fixing, re-run the request; marshmallow reports remaining fields on the next pass."],"exampleFix":"// before\nmetadata: {\"timed_refresh_immune_slices\": [\"34\"]}  // strings\n\n// after\nmetadata: {\"timed_refresh_immune_slices\": [34]}  // integers","handlingStrategy":"validation","validationCode":"from superset.dashboards.schemas import DashboardJSONMetadataSchema\n\nerrors = DashboardJSONMetadataSchema().validate(metadata_obj, partial=False)\nif errors:\n    raise ValueError(f\"metadata schema violations: {errors}\")","typeGuard":null,"tryCatchPattern":"from marshmallow import ValidationError\ntry:\n    validate_json_metadata(metadata)\nexcept ValidationError as ex:\n    errors = ex.messages  # dict: field -> [messages]\n    for field, msgs in (errors.items() if isinstance(errors, dict) else []):\n        print(field, msgs)","preventionTips":["Run DashboardJSONMetadataSchema().validate client-server side before saving.","Keep metadata shapes aligned with the running Superset version's schema.","Round-trip dashboards via export/import rather than scripted metadata mutation."],"tags":["json","validation","dashboard-metadata","schema"],"backgroundTag":null,"analyzedSha":"f4587218dd19d046c3e4d00063e7d27f8a2ed354","analyzedAt":"2026-08-14T22:39:27.425Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}