zed-industries/zed · error · RuntimeError

issue {number} has no created_at

Error message

issue {number} has no created_at

What it means

Raised when parse_dt(issue['created_at']) returns None inside fetch_issue(). parse_dt returns None only for falsy input, so GitHub returned HTTP 200 with an issue object whose created_at is null or an empty string. A genuinely missing key would raise KeyError instead — this error specifically means the field was present but empty.

Source

Thrown at script/triage_project_sync.py:263

    issue_type: str | None  # e.g. "Bug", "Crash", "Meta", "Tracking", or None
    is_pull_request: bool
    comments: list[dict]


def parse_dt(s: str | None) -> datetime | None:
    if not s:
        return None
    return datetime.fromisoformat(s.replace("Z", "+00:00"))


def fetch_issue(number: int) -> IssueData:
    issue = rest_get(f"repos/{REPO}/issues/{number}")
    if not isinstance(issue, dict):
        raise RuntimeError(f"unexpected response for issue {number}")
    comments = rest_get_paginated(f"repos/{REPO}/issues/{number}/comments")
    created_at = parse_dt(issue["created_at"])
    if created_at is None:
        raise RuntimeError(f"issue {number} has no created_at")
    issue_type = None
    if isinstance(issue.get("type"), dict):
        issue_type = issue["type"].get("name")
    return IssueData(
        number=number,
        node_id=issue["node_id"],
        title=issue["title"],
        state=issue["state"],
        closed_at=parse_dt(issue.get("closed_at")),
        created_at=created_at,
        reporter=issue["user"]["login"],
        assignees=[a["login"] for a in (issue.get("assignees") or [])],
        labels=[l["name"] for l in issue["labels"]],
        issue_type=issue_type,
        is_pull_request="pull_request" in issue,
        comments=comments,
    )

View on GitHub (pinned to bc538def45)

Solutions

  1. Re-run the sync — transient payload anomalies usually do not repeat for the same issue
  2. Dump the raw JSON for the failing issue number and confirm created_at is actually empty
  3. If persistent, check api.github.com status / GitHub Enterprise version and report the payload shape

Example fix

# before
created_at = parse_dt(issue["created_at"])
if created_at is None:
    raise RuntimeError(f"issue {number} has no created_at")

# after (skip anomalous issues with visibility instead of aborting the sync)
created_at = parse_dt(issue.get("created_at"))
if created_at is None:
    log(f"issue {number} has empty created_at; skipping", "WARN")
    continue
Defensive patterns

Strategy: validation

Validate before calling

# Validate the raw payload shape before building IssueData
issue = rest_get(f"repos/{REPO}/issues/{number}")
if not isinstance(issue.get("created_at"), str) or not issue["created_at"].strip():
    log(f"issue {number} has empty created_at; skipping", "WARN")
    continue

Type guard

def has_created_at(payload: dict) -> bool:
    value = payload.get("created_at")
    return isinstance(value, str) and value.strip() != ""

Try / catch

try:
    data = fetch_issue(number)
except RuntimeError as error:
    if "no created_at" in str(error):
        log(f"skipping anomalous issue {number}", "WARN")
        continue
    raise

Prevention

When it happens

Trigger: GET /repos/{REPO}/issues/{number} succeeds (200) but the body has "created_at": null or "" — a degraded or partially-truncated payload from GitHub, a caching proxy, or an Enterprise Server version with different behavior.

Common situations: Transient GitHub incident producing incomplete payloads; an HTTP cache serving a truncated body; GitHub Enterprise Server API contract drift; response body cut mid-transfer and parsed leniently.

Related errors


AI-assisted analysis of zed-industries/zed@bc538def45 (2026-08-16). Data as JSON: /api/errors/b64456763fee9480. Report an issue: GitHub.