apache/superset · error · ValidationError

{errors}

Error message

{errors}

What it means

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.

Source

Thrown at superset/dashboards/schemas.py:128


def validate_json(value: Union[bytes, bytearray, str]) -> None:
    try:
        json.validate_json(value)
    except json.JSONDecodeError as ex:
        raise ValidationError("JSON not valid") from ex


def validate_json_metadata(value: Union[bytes, bytearray, str]) -> None:
    if not value:
        return
    try:
        value_obj = json.loads(value)
    except json.JSONDecodeError as ex:
        raise ValidationError("JSON not valid") from ex
    errors = DashboardJSONMetadataSchema().validate(value_obj, partial=False)
    if errors:
        raise ValidationError(errors)


# Patterns for CSS constructs that can be abused to execute scripts or pull in
# remote stylesheets/resources. The custom CSS is stored verbatim and re-served
# into the dashboard page, so these are rejected at validation time. Ordinary
# styling (including ``url(...)`` referencing relative paths or ``data:`` image
# URIs) is left untouched.
_CSS_SCRIPT_SCHEME = r"(?:javascript|vbscript|livescript|mocha)\s*:"
_DANGEROUS_CSS_PATTERNS: tuple[tuple[str, "re.Pattern[str]"], ...] = (
    # Legacy IE dynamic expressions, e.g. ``width: expression(alert(1))``.
    ("expression(", re.compile(r"expression\s*\(", re.IGNORECASE)),
    # Inline script schemes anywhere in the declaration.
    ("script scheme", re.compile(_CSS_SCRIPT_SCHEME, re.IGNORECASE)),
    # Remote stylesheet imports.
    ("@import", re.compile(r"@import\b", re.IGNORECASE)),
    # url(...) pointing at a script scheme. Legitimate image/relative/data URLs
    # are intentionally not matched here.
    (

View on GitHub (pinned to f4587218dd)

Solutions

  1. Read the errors dict — each key names the offending metadata field and the message says the expected type.
  2. 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.
  3. Pull a known-good dashboard's metadata via the API and diff your payload against it field by field.
  4. After fixing, re-run the request; marshmallow reports remaining fields on the next pass.

Example fix

// before
metadata: {"timed_refresh_immune_slices": ["34"]}  // strings

// after
metadata: {"timed_refresh_immune_slices": [34]}  // integers
Defensive patterns

Strategy: validation

Validate before calling

from superset.dashboards.schemas import DashboardJSONMetadataSchema

errors = DashboardJSONMetadataSchema().validate(metadata_obj, partial=False)
if errors:
    raise ValueError(f"metadata schema violations: {errors}")

Try / catch

from marshmallow import ValidationError
try:
    validate_json_metadata(metadata)
except ValidationError as ex:
    errors = ex.messages  # dict: field -> [messages]
    for field, msgs in (errors.items() if isinstance(errors, dict) else []):
        print(field, msgs)

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of apache/superset@f4587218dd (2026-08-14). Data as JSON: /api/errors/0fe566e4010b6342. Report an issue: GitHub.