666ghj/MiroFish · error · StarHistoryError

GitHub returned an invalid star timestamp

Error message

GitHub returned an invalid star timestamp

What it means

_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.

Source

Thrown at scripts/star_history.py:311

            total_count=total_count,
            edges=tuple(edges),
            has_next_page=has_next_page,
            end_cursor=end_cursor,
            rate_remaining=rate_remaining,
        )


def _strict_non_negative_int(value: Any, label: str) -> int:
    if type(value) is not int or value < 0:
        raise StarHistoryError(f"{label} must be a non-negative integer")
    return value


def _parse_github_timestamp(value: str) -> datetime:
    try:
        parsed = datetime.fromisoformat(value.replace("Z", "+00:00"))
    except ValueError as exc:
        raise StarHistoryError("GitHub returned an invalid star timestamp") from exc
    if parsed.tzinfo is None or parsed.utcoffset() != timedelta(0):
        raise StarHistoryError("GitHub star timestamp was not UTC")
    return parsed.astimezone(UTC)


def _parse_state_timestamp(value: Any, label: str) -> datetime:
    if not isinstance(value, str) or not STATE_TIMESTAMP_RE.fullmatch(value):
        raise StarHistoryError(f"{label} must use YYYY-MM-DDTHH:MM:SSZ")
    try:
        parsed = datetime.strptime(value, "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=UTC)
    except ValueError as exc:
        raise StarHistoryError(f"{label} is not a valid UTC timestamp") from exc
    return parsed


def _format_state_timestamp(value: datetime) -> str:
    normalized = _normalize_now(value)
    return normalized.strftime("%Y-%m-%dT%H:%M:%SZ")

View on GitHub (pinned to b5b53acc57)

Solutions

  1. Normalize fixture timestamps to ISO 8601 with Z, e.g. '2024-01-15T10:30:00Z'
  2. Check the chained ValueError (__cause__) for the exact position where parsing failed
  3. If a proxy rewrites dates, bypass it or make it pass bodies through untouched

Example fix

// before (fixture)
"starredAt": "15 Jan 2024"

// after (fixture)
"starredAt": "2024-01-15T10:30:00Z"
Defensive patterns

Strategy: try-catch

Validate before calling

from datetime import datetime

def is_iso8601(value: str) -> bool:
    try:
        datetime.fromisoformat(value.replace("Z", "+00:00"))
        return True
    except ValueError:
        return False

if not all(is_iso8601(e.get("starredAt", "")) for e in raw_edges):
    raise StarHistoryError("non-ISO starredAt in payload")

Type guard

def is_parseable_github_timestamp(value: object) -> TypeGuard[str]:
    if not isinstance(value, str):
        return False
    try:
        datetime.fromisoformat(value.replace("Z", "+00:00"))
        return True
    except ValueError:
        return False

Try / catch

try:
    ts = _parse_github_timestamp(starred_at)
except StarHistoryError as exc:
    logger.error("unparseable starredAt %r", starred_at)
    raise  # do not drop stars silently; the count would drift from totalCount

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of 666ghj/MiroFish@b5b53acc57 (2026-08-14). Data as JSON: /api/errors/2dcd92df7053560d. Report an issue: GitHub.