apache/superset · error · ValidationError

Not a valid list

Error message

Not a valid list

What it means

SharedLabelsColorsField deserializes the shared-labels color config: it accepts a list of strings (the current format), returns [] when given a dict (legacy backward compatibility), and rejects everything else with 'Not a valid list'. It is a custom marshmallow field on the dashboard schema.

Source

Thrown at superset/dashboards/schemas.py:195

    """
    A custom field that accepts either a list of strings or a dictionary.
    """

    def _deserialize(
        self,
        value: Union[list[str], dict[str, str]],
        attr: Union[str, None],
        data: Union[Mapping[str, Any], None],
        **kwargs: dict[str, Any],
    ) -> list[str]:
        if isinstance(value, list):
            if all(isinstance(item, str) for item in value):
                return value
        elif isinstance(value, dict):
            # Enforce list (for backward compatibility)
            return []

        raise ValidationError("Not a valid list")


class DashboardJSONMetadataSchema(Schema):
    # native_filter_configuration is for dashboard-native filters
    native_filter_configuration = fields.List(fields.Dict(), allow_none=True)
    # chart_configuration for now keeps data about cross-filter scoping for charts
    chart_configuration = fields.Dict()
    # global_chart_configuration keeps data about global cross-filter scoping
    # for charts - can be overridden by chart_configuration for each chart
    global_chart_configuration = fields.Dict()
    chart_customization_config = fields.List(fields.Dict(), allow_none=True)
    timed_refresh_immune_slices = fields.List(fields.Integer())
    # deprecated wrt dashboard-native filters
    filter_scopes = fields.Dict()
    expanded_slices = fields.Dict()
    expand_all_slices = fields.Boolean()
    refresh_frequency = fields.Integer()
    # deprecated wrt dashboard-native filters

View on GitHub (pinned to f4587218dd)

Solutions

  1. Send shared_labels_colors as an array of strings, e.g. ["#00ff00", "#ff0000"].
  2. If you have a dict from an old export, either drop it (it becomes []) or convert its values to a list of strings yourself.
  3. Map/validate values client-side: colors.every(c => typeof c === 'string').

Example fix

// before
shared_labels_colors: { "label1": "#00ff00" }  // legacy dict, coerced to []
shared_labels_colors: [1, 2]  // rejected

// after
shared_labels_colors: ["#00ff00", "#0000ff"]
Defensive patterns

Strategy: type-guard

Type guard

function isSharedLabelsColors(v: unknown): v is string[] {
  return Array.isArray(v) && v.every(x => typeof x === 'string');
}

Prevention

When it happens

Trigger: PUT/POST /api/v1/dashboard/ with shared_labels_colors set to a non-list/non-dict value: a bare string, a number, null in a disallowed position, or a list containing non-string items (e.g. [1, 2]).

Common situations: API clients building the payload dynamically and passing an object where a list of color strings is expected; list items accidentally numbers; older payloads sending dicts (accepted, silently normalized to []).

Related errors


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