{"record":{"id":"753dbf21c3d38c67","repo":"zed-industries/zed","slug":"failed-to-connect-to-sentry-api-err-reason","errorCode":null,"errorMessage":"Failed to connect to Sentry API: {err.reason}","messagePattern":"Failed to connect to Sentry API: (.+?)","errorType":"exception","errorClass":"FetchError","httpStatus":null,"severity":"error","filePath":"script/sentry-fetch","lineNumber":110,"sourceCode":"\ndef api_get(path, token):\n    \"\"\"Make an authenticated GET request to the Sentry API.\"\"\"\n    url = f\"{SENTRY_BASE_URL}{path}\"\n    req = urllib.request.Request(url)\n    req.add_header(\"Authorization\", f\"Bearer {token}\")\n    req.add_header(\"Accept\", \"application/json\")\n    try:\n        with urllib.request.urlopen(req) as response:\n            return json.loads(response.read().decode(\"utf-8\"))\n    except urllib.error.HTTPError as err:\n        body = err.read().decode(\"utf-8\", errors=\"replace\")\n        try:\n            detail = json.loads(body).get(\"detail\", body)\n        except (json.JSONDecodeError, AttributeError):\n            detail = body\n        raise FetchError(f\"Sentry API returned HTTP {err.code} for {path}: {detail}\")\n    except urllib.error.URLError as err:\n        raise FetchError(f\"Failed to connect to Sentry API: {err.reason}\")\n\n\ndef resolve_issue(identifier, token):\n    \"\"\"Resolve a Sentry issue by short ID or numeric ID.\n\n    Returns (issue_id, short_id, issue_data).\n    \"\"\"\n    if identifier.isdigit():\n        issue = api_get(f\"/issues/{identifier}/\", token)\n        return identifier, issue.get(\"shortId\", identifier), issue\n\n    result = api_get(f\"/organizations/{DEFAULT_SENTRY_ORG}/shortids/{identifier}/\", token)\n    group_id = str(result[\"groupId\"])\n    issue = api_get(f\"/issues/{group_id}/\", token)\n    return group_id, identifier, issue\n\n\ndef fetch_latest_event(issue_id, token):","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/zed-industries/zed/blob/bc538def4545534201bbfcac4e95ac34ea6501b6/script/sentry-fetch#L92-L128","documentation":"Raised by api_get() in script/sentry-fetch when urllib raises URLError before any HTTP response arrives: DNS failure, connection refused, TLS error, or proxy failure. Note this script's urlopen(req) passes no timeout argument, so a silently hanging connection can also manifest here only once the OS gives up — or the script can appear to hang indefinitely before erroring.","triggerScenarios":"No network route to sentry.io from where sentry-fetch runs; required HTTPS_PROXY missing; DNS failure for the Sentry host; TLS interception with an untrusted CA; Sentry outage.","commonSituations":"Cron/devbox without proxy env vars; container with broken resolv.conf; corporate MITM proxy cert not in the Python trust store; running offline.","solutions":["Verify basic reachability: curl -sS https://sentry.io/api/0/ from the same shell","Export HTTPS_PROXY if the environment requires an egress proxy","Add a timeout to urllib.request.urlopen(req, timeout=30) so hangs fail fast instead of blocking","Check status.sentry.io for incidents"],"exampleFix":"# before\nwith urllib.request.urlopen(req) as response:\n    return json.loads(response.read().decode(\"utf-8\"))\n\n# after\nwith urllib.request.urlopen(req, timeout=30) as response:\n    return json.loads(response.read().decode(\"utf-8\"))","handlingStrategy":"retry","validationCode":"# Pre-flight egress and set proxy env before importing/running\nimport os, socket\n\nfor host in (\"sentry.io\",):\n    try:\n        socket.create_connection((host, 443), timeout=5).close()\n    except OSError as error:\n        if not os.environ.get(\"HTTPS_PROXY\"):\n            print(\"no egress and no HTTPS_PROXY set — set it and retry\")\n        raise","typeGuard":null,"tryCatchPattern":"try:\n    data = api_get(path, token)\nexcept FetchError as error:\n    if \"Failed to connect\" not in str(error):\n        raise\n    if attempt < max_retries:\n        time.sleep(2 ** attempt); continue\n    raise","preventionTips":["Pass a timeout to urllib.request.urlopen so network hangs fail fast","Install corporate proxy CAs into the trust store for TLS-intercepting environments","Wrap batch fetches with per-item try/except so one connectivity blip does not lose the run"],"tags":["python","sentry","network","proxy","timeout"],"backgroundTag":null,"analyzedSha":"bc538def4545534201bbfcac4e95ac34ea6501b6","analyzedAt":"2026-08-16T07:30:46.435Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}