mvanhorn/last30days-skill · warning · KeyError

Polymarket event is closed, unavailable, or malformed

Error message

Polymarket event is closed, unavailable, or malformed

What it means

KeyError raised when the Gamma event was found but parse_polymarket_response produced no items from it. The parse uses include_closed=not has_active, so this fires when the event exists yet contains no markets matching the active/closed filter - i.e. it is closed, unavailable, or its markets array is malformed.

Solutions

  1. Catch KeyError and present the last known value with an 'event closed' note instead of failing the whole verification pass
  2. Skip re-verification for events whose updatedAt is old relative to the original fetch
  3. For genuinely closed events, route users to the resolution outcome rather than odds

Example fix

# before
refreshed = refetch_datum(item, "Yes")

# after
try:
    refreshed = refetch_datum(item, "Yes")
except KeyError:
    return {"value": cached_value, "stale": True, "note": "event closed or unavailable"}
Defensive patterns

Strategy: fallback

Try / catch

try:
    datum = refetch_datum(item, key)
except KeyError as e:
    if "closed, unavailable, or malformed" in str(e):
        datum = {"value": cached_value, "stale": True}

Prevention

When it happens

Trigger: Event dict whose markets list is empty or non-dict entries only (has_active False, include_closed True, still nothing parses); event fully resolved whose child markets fail the closed-market parsing; event with active=True markets that are all closed=True so they are excluded when has_active is False.

Common situations: Re-verifying odds on a market that resolved between original fetch and refresh; Gamma returning events with markets stripped out; schema drift in Gamma market fields breaking the parser.

Understand the failure class

Related errors


AI-assisted analysis of mvanhorn/last30days-skill@c7460f6114 (2026-08-15). Data as JSON: /api/errors/4bebc466d667d49a. Report an issue: GitHub.

Appendix: source

Thrown at skills/last30days/scripts/lib/polymarket.py:1017

            event = None
    if not isinstance(event, dict):
        raise KeyError("Polymarket event was not found")
    # Mixed events: an active event can carry resolved child markets whose
    # high volume would win the parse and swap the outcome labels. Only fall
    # back to closed markets when nothing is active (fully resolved event -
    # the stale-odds transition verification exists to catch).
    markets = event.get("markets") or []
    has_active = any(
        isinstance(m, dict) and m.get("active", True) and not m.get("closed", False)
        for m in markets
    )
    parsed = parse_polymarket_response(
        {"events": [event]},
        include_all_outcomes=True,
        include_closed=not has_active,
    )
    if not parsed:
        raise KeyError("Polymarket event is closed, unavailable, or malformed")
    refreshed = parsed[0]
    values: dict[str, Any] = {}
    outcome_pairs = refreshed.get("outcome_prices") or []
    outcome_totals: dict[str, int] = {}
    for name, _price in outcome_pairs:
        normalized = str(name).casefold()
        outcome_totals[normalized] = outcome_totals.get(normalized, 0) + 1
    outcome_counts: dict[str, int] = {}
    for name, price in outcome_pairs:
        normalized = str(name).casefold()
        occurrence = outcome_counts.get(normalized, 0)
        outcome_counts[normalized] = occurrence + 1
        key = f"{name}\x1f{occurrence}" if outcome_totals[normalized] > 1 else str(name)
        values[key] = price
    if refreshed.get("end_date") is not None:
        values["end_date"] = refreshed["end_date"]

    if datum_key == "end_date":

View on GitHub (pinned to c7460f6114)