Skip to content

[Task]: datetime.min fallback in DatabaseTaskStore.list() is outside MySQL's documented DATETIME range #1219

Description

@sokoliva

What happened?

DatabaseTaskStore.list() uses datetime.min (year 0001) as the COALESCE fallback for NULL timestamps in its ORDER BY:
https://github.com/a2aproject/a2a-python/blob/main/src/a2a/server/tasks/database_task_store.py#L248-L256

# Use coalesce to treat NULL timestamps as datetime.min,
# which sort last in descending order
stmt = base_stmt.order_by(
    func.coalesce(
        timestamp_col,
        datetime.min.replace(tzinfo=timezone.utc),
    ).desc(),
    self.task_model.id.desc(),
)

Per the MySQL DATETIME documentation, the supported range is '1000-01-01 00:00:00' to '9999-12-31 23:59:59'. Year 0001 is outside that range.
Raised by @lkk7 in review: comment

To be clear about severity: this is mostly a spec-conformance issue, not a replicable bug. I could not make it fail, but still worth fixing since the MySQL spec states "For the DATE and DATETIME range descriptions, “supported” means that although earlier values might work, there is no guarantee."

Prior attempts that did NOT work — please don't reintroduce

This line has already been changed a couple of times. Recording so the next fix does not cycle back:
timestamp_col.desc().nulls_last() — BROKEN on MySQL. Removed in #651 (fix: use MySQL compatible syntax in list tasks) because MySQL has no NULLS LAST syntax.

Relevant log output

MySQL version: 8.0.46
sql_mode:      ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION

Saved 5 tasks (2 with NULL last_updated)

Raw rows as stored in MySQL (ordered by the SDK expression):
  id     last_updated                 coalesce fallback
  t-A    2025-01-03 00:00:00          2025-01-03 00:00:00
  t-E    2025-01-02 00:00:00          2025-01-02 00:00:00
  t-C    2025-01-01 00:00:00          2025-01-01 00:00:00
  t-D    None                         0001-01-01 00:00:00
  t-B    None                         0001-01-01 00:00:00


COALESCE output JSON type: STRING

full list order: ['t-A', 't-E', 't-C', 't-D', 't-B']
  page 1: ['t-A', 't-E']
  page 2: ['t-C', 't-D']
  page 3: ['t-B']
paginated: ['t-A', 't-E', 't-C', 't-D', 't-B']

PASS: list() works on MySQL with NULL timestamps.

Code of Conduct

  • I agree to follow this project's Code of Conduct

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions