{"record":{"id":"2dcd92df7053560d","repo":"666ghj/MiroFish","slug":"github-returned-an-invalid-star-timestamp","errorCode":null,"errorMessage":"GitHub returned an invalid star timestamp","messagePattern":"GitHub returned an invalid star timestamp","errorType":"exception","errorClass":"StarHistoryError","httpStatus":null,"severity":"error","filePath":"scripts/star_history.py","lineNumber":311,"sourceCode":"            total_count=total_count,\n            edges=tuple(edges),\n            has_next_page=has_next_page,\n            end_cursor=end_cursor,\n            rate_remaining=rate_remaining,\n        )\n\n\ndef _strict_non_negative_int(value: Any, label: str) -> int:\n    if type(value) is not int or value < 0:\n        raise StarHistoryError(f\"{label} must be a non-negative integer\")\n    return value\n\n\ndef _parse_github_timestamp(value: str) -> datetime:\n    try:\n        parsed = datetime.fromisoformat(value.replace(\"Z\", \"+00:00\"))\n    except ValueError as exc:\n        raise StarHistoryError(\"GitHub returned an invalid star timestamp\") from exc\n    if parsed.tzinfo is None or parsed.utcoffset() != timedelta(0):\n        raise StarHistoryError(\"GitHub star timestamp was not UTC\")\n    return parsed.astimezone(UTC)\n\n\ndef _parse_state_timestamp(value: Any, label: str) -> datetime:\n    if not isinstance(value, str) or not STATE_TIMESTAMP_RE.fullmatch(value):\n        raise StarHistoryError(f\"{label} must use YYYY-MM-DDTHH:MM:SSZ\")\n    try:\n        parsed = datetime.strptime(value, \"%Y-%m-%dT%H:%M:%SZ\").replace(tzinfo=UTC)\n    except ValueError as exc:\n        raise StarHistoryError(f\"{label} is not a valid UTC timestamp\") from exc\n    return parsed\n\n\ndef _format_state_timestamp(value: datetime) -> str:\n    normalized = _normalize_now(value)\n    return normalized.strftime(\"%Y-%m-%dT%H:%M:%SZ\")","sourceCodeStart":293,"sourceCodeEnd":329,"githubUrl":"https://github.com/666ghj/MiroFish/blob/b5b53acc57189a4a42e44a23e149dc655c98fe82/scripts/star_history.py#L293-L329","documentation":"_parse_github_timestamp called datetime.fromisoformat on the starredAt string (with 'Z' rewritten to '+00:00') and Python raised ValueError — the string is not parseable as ISO 8601 at all. The ValueError is chained (raise ... from exc) into StarHistoryError('GitHub returned an invalid star timestamp') so the original parse failure stays visible in the traceback.","triggerScenarios":"starredAt values like 'not-a-date', '2024/01/15', 'Jan 15 2024', or an empty string; typically from fixtures or a non-GitHub-compatible API, since real GitHub always emits strict ISO 8601.","commonSituations":"Hand-written test fixtures with sloppy date strings; pointing the script at a GitHub Enterprise or proxy whose date format differs; string concatenation bugs corrupting timestamps in stubs.","solutions":["Normalize fixture timestamps to ISO 8601 with Z, e.g. '2024-01-15T10:30:00Z'","Check the chained ValueError (__cause__) for the exact position where parsing failed","If a proxy rewrites dates, bypass it or make it pass bodies through untouched"],"exampleFix":"// before (fixture)\n\"starredAt\": \"15 Jan 2024\"\n\n// after (fixture)\n\"starredAt\": \"2024-01-15T10:30:00Z\"","handlingStrategy":"try-catch","validationCode":"from datetime import datetime\n\ndef is_iso8601(value: str) -> bool:\n    try:\n        datetime.fromisoformat(value.replace(\"Z\", \"+00:00\"))\n        return True\n    except ValueError:\n        return False\n\nif not all(is_iso8601(e.get(\"starredAt\", \"\")) for e in raw_edges):\n    raise StarHistoryError(\"non-ISO starredAt in payload\")","typeGuard":"def is_parseable_github_timestamp(value: object) -> TypeGuard[str]:\n    if not isinstance(value, str):\n        return False\n    try:\n        datetime.fromisoformat(value.replace(\"Z\", \"+00:00\"))\n        return True\n    except ValueError:\n        return False","tryCatchPattern":"try:\n    ts = _parse_github_timestamp(starred_at)\nexcept StarHistoryError as exc:\n    logger.error(\"unparseable starredAt %r\", starred_at)\n    raise  # do not drop stars silently; the count would drift from totalCount","preventionTips":["Generate all fixture timestamps with datetime.strftime('%Y-%m-%dT%H:%M:%SZ')","Inspect exc.__cause__ (the ValueError) to find exactly where ISO parsing failed"],"tags":["datetime","parsing","validation","iso8601","star-history"],"backgroundTag":null,"analyzedSha":"b5b53acc57189a4a42e44a23e149dc655c98fe82","analyzedAt":"2026-08-14T22:29:33.146Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}