{"record":{"id":"4bebc466d667d49a","repo":"mvanhorn/last30days-skill","slug":"polymarket-event-is-closed-unavailable-or-malfor","errorCode":null,"errorMessage":"Polymarket event is closed, unavailable, or malformed","messagePattern":"Polymarket event is closed, unavailable, or malformed","errorType":"exception","errorClass":"KeyError","httpStatus":null,"severity":"warning","filePath":"skills/last30days/scripts/lib/polymarket.py","lineNumber":1017,"sourceCode":"            event = None\n    if not isinstance(event, dict):\n        raise KeyError(\"Polymarket event was not found\")\n    # Mixed events: an active event can carry resolved child markets whose\n    # high volume would win the parse and swap the outcome labels. Only fall\n    # back to closed markets when nothing is active (fully resolved event -\n    # the stale-odds transition verification exists to catch).\n    markets = event.get(\"markets\") or []\n    has_active = any(\n        isinstance(m, dict) and m.get(\"active\", True) and not m.get(\"closed\", False)\n        for m in markets\n    )\n    parsed = parse_polymarket_response(\n        {\"events\": [event]},\n        include_all_outcomes=True,\n        include_closed=not has_active,\n    )\n    if not parsed:\n        raise KeyError(\"Polymarket event is closed, unavailable, or malformed\")\n    refreshed = parsed[0]\n    values: dict[str, Any] = {}\n    outcome_pairs = refreshed.get(\"outcome_prices\") or []\n    outcome_totals: dict[str, int] = {}\n    for name, _price in outcome_pairs:\n        normalized = str(name).casefold()\n        outcome_totals[normalized] = outcome_totals.get(normalized, 0) + 1\n    outcome_counts: dict[str, int] = {}\n    for name, price in outcome_pairs:\n        normalized = str(name).casefold()\n        occurrence = outcome_counts.get(normalized, 0)\n        outcome_counts[normalized] = occurrence + 1\n        key = f\"{name}\\x1f{occurrence}\" if outcome_totals[normalized] > 1 else str(name)\n        values[key] = price\n    if refreshed.get(\"end_date\") is not None:\n        values[\"end_date\"] = refreshed[\"end_date\"]\n\n    if datum_key == \"end_date\":","sourceCodeStart":999,"sourceCodeEnd":1035,"githubUrl":"https://github.com/mvanhorn/last30days-skill/blob/c7460f6114449ddfe6ea3fc2f23c3d910c0e740c/skills/last30days/scripts/lib/polymarket.py#L999-L1035","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Catch KeyError and present the last known value with an 'event closed' note instead of failing the whole verification pass","Skip re-verification for events whose updatedAt is old relative to the original fetch","For genuinely closed events, route users to the resolution outcome rather than odds"],"exampleFix":"# before\nrefreshed = refetch_datum(item, \"Yes\")\n\n# after\ntry:\n    refreshed = refetch_datum(item, \"Yes\")\nexcept KeyError:\n    return {\"value\": cached_value, \"stale\": True, \"note\": \"event closed or unavailable\"}","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    datum = refetch_datum(item, key)\nexcept KeyError as e:\n    if \"closed, unavailable, or malformed\" in str(e):\n        datum = {\"value\": cached_value, \"stale\": True}","preventionTips":["Check event['closed'] / market resolution status before requesting an odds refresh","Present last-known values with a staleness note for resolved events","Compare event['updatedAt'] to the original fetch time to skip pointless refreshes"],"tags":["polymarket","api","keyerror","stale-data"],"backgroundTag":null,"analyzedSha":"c7460f6114449ddfe6ea3fc2f23c3d910c0e740c","analyzedAt":"2026-08-15T03:34:49.540Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}