Skip to content

gamma: Event._normalize_event uses snake_case key "published_at" instead of camelCase "publishedAt", causing event.published_at to always be None #62

@Nexory

Description

@Nexory

Current code

src/polymarket/models/gamma/event.py, line 322

            "featured_image": data.get("featuredImage"),
            "created_at": data.get("createdAt"),
            "updated_at": data.get("updatedAt"),
            "published_at": data.get("published_at"),   # BUG: should be "publishedAt"
            "state": {

Adjacent fields on lines 319–321 all correctly read camelCase keys from the raw API dict ("featuredImage", "createdAt", "updatedAt"). Line 322 alone uses the Python snake_case key "published_at", which will never be present in a raw Gamma API response.

The field declaration at line 272 is:

published_at: datetime | None = Field(default=None, validation_alias="publishedAt")

The validation_alias is only consulted by Pydantic on the direct-parse path (when "state" is already present in the incoming dict — early return at lines 305–306). For every real Gamma API response, _normalize_event runs in mode="before" and constructs a new dict manually; the alias is never consulted on that code path. data.get("published_at") therefore always returns None.

Bug introduced in commit 17f6fdc. None of the four subsequent commits that touched event.py (0138ad6, 60c694a, 4f1fd57) corrected it. It went undetected because the test fixture in test_event_normalizes_groups_from_flat_payload omits publishedAt entirely and makes no assertion on published_at.

Reproduction

from polymarket.models.gamma import Event

raw = {
    "id": "123",
    "publishedAt": "2026-01-01T00:00:00Z",
    "createdAt": "2026-02-01T00:00:00Z",
    "updatedAt": "2026-03-01T00:00:00Z",
}

event = Event.parse_response(raw)

assert event.created_at is not None   # passes — "createdAt" key is correct
assert event.updated_at is not None   # passes — "updatedAt" key is correct
assert event.published_at is None     # passes — demonstrates the bug

event.published_at is always None for any event returned from the live Gamma API, regardless of what the server sends.

Impact

Any caller that reads event.published_at (e.g. to sort or filter events by publish date) silently gets None for every live API response. Because the field type is datetime | None, no exception is raised and the data loss goes unnoticed. This affects the raw /events and /events/{id} Gamma endpoints — i.e., essentially all real usage of the Event model.

Suggested fix

One-line fix on line 322:

# before
"published_at": data.get("published_at"),

# after
"published_at": data.get("publishedAt"),

Recommend also adding coverage in test_event_normalizes_groups_from_flat_payload:

# fixture: add publishedAt="2026-01-01T00:00:00Z"
assert event.published_at == datetime(2026, 1, 1, tzinfo=UTC)

That assertion would have caught this at introduction time.

Related

  • The same normalizer block is the source of truth for all datetime hydration on the raw-API path; the other three fields in the same block (featuredImage, createdAt, updatedAt) are correct and serve as the reference pattern.
  • Repo is on latest commit 588d664 (2026-05-27) — confirmed not fixed upstream.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions