zed-industries/zed · error · FetchError

Sentry API returned HTTP {err.code} for {path}: {detail}

Error message

Sentry API returned HTTP {err.code} for {path}: {detail}

What it means

Raised by api_get() in script/sentry-fetch when the Sentry API returns a 4xx/5xx (urllib HTTPError). Unlike its counterpart in select-sentry-crash-candidates, this urlopen call sets no timeout, so the HTTPError path is reached only after the server actually responded with an error status. The detail is Sentry's JSON 'detail' when parseable, else the raw body.

Source

Thrown at script/sentry-fetch:108

    return None


def api_get(path, token):
    """Make an authenticated GET request to the Sentry API."""
    url = f"{SENTRY_BASE_URL}{path}"
    req = urllib.request.Request(url)
    req.add_header("Authorization", f"Bearer {token}")
    req.add_header("Accept", "application/json")
    try:
        with urllib.request.urlopen(req) as response:
            return json.loads(response.read().decode("utf-8"))
    except urllib.error.HTTPError as err:
        body = err.read().decode("utf-8", errors="replace")
        try:
            detail = json.loads(body).get("detail", body)
        except (json.JSONDecodeError, AttributeError):
            detail = body
        raise FetchError(f"Sentry API returned HTTP {err.code} for {path}: {detail}")
    except urllib.error.URLError as err:
        raise FetchError(f"Failed to connect to Sentry API: {err.reason}")


def resolve_issue(identifier, token):
    """Resolve a Sentry issue by short ID or numeric ID.

    Returns (issue_id, short_id, issue_data).
    """
    if identifier.isdigit():
        issue = api_get(f"/issues/{identifier}/", token)
        return identifier, issue.get("shortId", identifier), issue

    result = api_get(f"/organizations/{DEFAULT_SENTRY_ORG}/shortids/{identifier}/", token)
    group_id = str(result["groupId"])
    issue = api_get(f"/issues/{group_id}/", token)
    return group_id, identifier, issue

View on GitHub (pinned to bc538def45)

Solutions

  1. Confirm the issue exists in the org the script targets (DEFAULT_SENTRY_ORG) via the Sentry UI
  2. For short IDs, pass the exact short_id shown by Sentry for that org
  3. Refresh the SENTRY_TOKEN and confirm event:read/org:read scopes
  4. Treat 404 as 'issue gone' and skip it rather than aborting the whole batch

Example fix

# before
if identifier.isdigit():
    issue = api_get(f"/issues/{identifier}/", token)

# after: distinguish gone-vs-auth failures for batch runs
try:
    issue = api_get(f"/issues/{identifier}/", token)
except FetchError as error:
    if "HTTP 404" in str(error):
        log(f"issue {identifier} no longer exists; skipping")
        continue
    raise
Defensive patterns

Strategy: try-catch

Validate before calling

# Validate identifier shape before resolving
if not (identifier.isdigit() or ("-" in identifier and len(identifier.split("-")) == 2)):
    sys.exit(f"not a numeric id or SHORTID: {identifier!r}")

Type guard

def is_numeric_issue_id(identifier: str) -> bool:
    return identifier.isdigit()

Try / catch

try:
    issue_id, short_id, issue = resolve_issue(identifier, token)
except FetchError as error:
    if "HTTP 404" in str(error):
        print(f"{identifier}: not found in org {DEFAULT_SENTRY_ORG}; skipping")
        continue
    if "HTTP 401" in str(error):
        sys.exit("SENTRY_TOKEN rejected — refresh it")
    raise

Prevention

When it happens

Trigger: resolve_issue() hitting /issues/{id}/ with an unknown numeric id (404); /organizations/{DEFAULT_SENTRY_ORG}/shortids/{short}/ with a short ID from another org (404); /issues/{id}/events/latest/ on a deleted issue (404); 401 from a revoked token; 403 from a token missing event:read scope.

Common situations: DEFAULT_SENTRY_ORG in the script does not match where the crash issue lives; token expired between cron runs; issue was resolved-and-deleted in Sentry before the fetch; typo'd short ID like ABC-123 vs the plain short part.

Related errors


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