apache/superset · error · ValueError

python_date_format is an invalid date/timestamp format.

Error message

python_date_format is an invalid date/timestamp format.

What it means

ValueError raised by DatasetDAO._validate_column_date_formats while updating a dataset: a column in the payload carries a non-None `python_date_format` that fails DatasetDAO.validate_python_date_format (a datetime.strptime round-trip check). It fires before super().update() persists anything.

Source

Thrown at superset/daos/dataset.py:447

            if "metrics" in attributes:
                cls.update_metrics(item, attributes.pop("metrics"))
                force_update = True

            if force_update:
                attributes["changed_on"] = datetime.now()

        return super().update(item, attributes)

    @classmethod
    def _validate_column_date_formats(
        cls, property_columns: list[dict[str, Any]]
    ) -> None:
        for column in property_columns:
            if column.get("python_date_format") is None:
                continue
            if not DatasetDAO.validate_python_date_format(column["python_date_format"]):
                raise ValueError(
                    "python_date_format is an invalid date/timestamp format."
                )

    @classmethod
    def _override_columns(
        cls, model: SqlaTable, property_columns: list[dict[str, Any]]
    ) -> None:
        """Replace columns by natural key (``column_name``) — update in place
        rather than delete-and-reinsert.

        SPIKE (full-Continuum): the previous
        delete-and-reinsert pattern produced overlapping shadow rows in
        ``table_columns_version`` (the same ``column_name`` had a DELETE
        shadow at tx N alongside an INSERT shadow at tx N for a fresh PK).
        Continuum's ``Reverter`` couldn't unwind this on restore: its flush
        ordering inserts the historical row before deleting the live one,
        hitting the ``UNIQUE (table_id, column_name)`` constraint mid-flush
        (ADR-004 Failure 1).

View on GitHub (pinned to f4587218dd)

Solutions

  1. Convert the format to Python strptime syntax: '%Y-%m-%d %H:%M:%S' etc. (moment-style 'YYYY-MM-DD' is the most common mistake).
  2. Leave python_date_format null to let Superset infer temporal formatting.
  3. Validate candidate formats client-side with datetime.strptime(now, fmt) before submitting.

Example fix

# before
columns=[{"column_name": "dt", "python_date_format": "YYYY-MM-DD"}]

# after
columns=[{"column_name": "dt", "python_date_format": "%Y-%m-%d"}]
Defensive patterns

Strategy: validation

Validate before calling

from datetime import datetime

def valid_python_date_format(fmt: str | None) -> bool:
    if fmt is None:
        return True
    try:
        datetime.now().strftime(fmt)  # round-trip sanity
        datetime.strptime(datetime.now().strftime(fmt), fmt)
        return True
    except (ValueError, TypeError):
        return False

Type guard

import re

def is_strptime_format(fmt: str) -> bool:
    # reject common moment/Java-style tokens
    return not re.search(r"(?<!%)YYYY|(?<!%)MM|(?<!%)DD|yyyy|dd", fmt)

Try / catch

try:
    DatasetDAO.update(dataset, {"columns": columns})
except ValueError as ex:
    if 'python_date_format' in str(ex):
        # fix the offending format tokens and resubmit once
        ...

Prevention

When it happens

Trigger: PUT/PATCH /api/v1/dataset/<id> (or column-edit flows) with columns[] entries whose python_date_format is not a valid Python strptime pattern — e.g. 'YYYY-MM-DD' (moment/ISO-style) instead of '%Y-%m-%d', or a typo like '%Y-%m-%'.

Common situations: Confusing Superset's two format dialects: python_date_format expects strptime codes while `db_engine_spec`-side/Java or moment-style tokens ('yyyy-MM-dd') belong elsewhere; integrations writing column payloads generated from JSON Schema examples with moment tokens.

Related errors


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