can1357/oh-my-pi · error · HTTPException
github error: {exc.status} {exc.message}
Error message
github error: {exc.status} {exc.message} What it means
A GitHubError escaped the triage call and api_trigger converts it into HTTP 502 with the message 'github error: {status} {message}'. The server successfully received your request but its call to the GitHub API failed with HTTP status `exc.status` and message `exc.message`. This marks an upstream dependency failure rather than a problem with your request.
Source
Thrown at python/robomp/src/server.py:632
try:
repo_full, number = parse_issue_ref(issue_ref)
except InvalidIssueRef as exc:
raise HTTPException(400, str(exc)) from exc
if not cfg.allows(repo_full):
raise HTTPException(403, f"{repo_full} not in ROBOMP_REPO_ALLOWLIST")
try:
delivery = await enqueue_manual_triage(
db=db,
github=github,
repo_full=repo_full,
number=number,
)
except ManualTriageConflict as exc:
raise HTTPException(409, str(exc)) from exc
except ManualTriageError as exc:
raise HTTPException(400, str(exc)) from exc
except GitHubError as exc:
raise HTTPException(502, f"github error: {exc.status} {exc.message}") from exc
pool.wake()
log.info("manual triage", extra={"delivery": delivery, "issue": f"{repo_full}#{number}"})
return JSONResponse(
{"delivery": delivery, "state": "queued", "mode": "triage"},
status_code=202,
)
# mode == "retry"
if isinstance(delivery_id, str) and delivery_id:
target = delivery_id
elif isinstance(issue_ref, str) and issue_ref:
try:
repo_full, number = parse_issue_ref(issue_ref)
except InvalidIssueRef as exc:
raise HTTPException(400, str(exc)) from exc
if not cfg.allows(repo_full):
raise HTTPException(403, f"{repo_full} not in ROBOMP_REPO_ALLOWLIST")
row = db.latest_event_for_issue(make_issue_key(repo_full, number))View on GitHub (pinned to 9690622007)
Solutions
- Read `exc.status` and `exc.message` from the 502 body — they mirror GitHub's own response and pinpoint the cause
- If 401/403: verify and refresh the GitHub token used by the server and confirm it has access to the target repo
- If 403 with rate-limit message: wait for the rate-limit window to reset or use a token with a higher quota
- If 404: confirm the repo exists and the token can see it (private repo membership)
- If 5xx: check GitHub status and retry the trigger once the upstream recovers
Example fix
// before: token from stale env client = GitHub(token=os.environ['OLD_GH_TOKEN']) // after: refreshed token with required scopes client = GitHub(token=os.environ['GH_TOKEN']) # updated secret, repo scope granted
Defensive patterns
Strategy: retry
Validate before calling
// Pre-flight: verify the token can read the target repo before triggering triage
const check = await fetch(`https://api.github.com/repos/${repoFull}`, {
headers: { Authorization: `Bearer ${ghToken}`, Accept: 'application/vnd.github+json' },
});
if (!check.ok) throw new Error(`GitHub pre-flight failed: ${check.status} ${await check.text()}`); Type guard
function isGitHubErrorDetail(body: unknown): body is { detail: string } & { status: number } {
return typeof body === 'object' && body !== null &&
typeof (body as any).detail === 'string' && /^github error: \d{3} /.test((body as any).detail);
} Try / catch
try {
await api.trigger(payload);
} catch (err) {
const m = /^github error: (\d{3}) /.exec(err.message ?? '');
if (m) {
const gh = Number(m[1]);
if (gh === 403 && /rate limit/i.test(err.message)) await Bun.sleep(rateLimitResetMs);
else if (gh >= 500) await Bun.sleep(retryMs); // transient GitHub outage
else logger.error('GitHub rejected the server call', { gh, detail: err.message }); // 401/403/404: fix token/repo
} else throw err;
} Prevention
- Rotate and verify the server's GitHub token before it expires
- Grant the token access to every repo in ROBOMP_REPO_ALLOWLIST, including private ones
- Monitor GitHub rate-limit headers and throttle webhook-triggered triage accordingly
- Subscribe to GitHub status updates; suppress auto-retries during incidents
When it happens
Trigger: Any trigger request where the triage path performs GitHub API calls (fetching the issue, labels, permissions, or posting triage results) and GitHub responds with a non-OK status — 401/403 for bad or expired tokens, 404 for a repo the token cannot see, 422 for invalid API input, 403 with rate-limit headers when the token is exhausted.
Common situations: ROBOMP GitHub token expired or rotated without updating the server config; token lacking access to a private repo in the allowlist; hitting GitHub's rate limit during webhook storms; a branch/issue being deleted between triage queuing and execution; GitHub incidents/5xx outages.
Related errors
- Gist fetch failed: HTTP ${res.status}
- exceptionType
- code
- Devin API error ${response.status} ${response.statusText}: $
- Too many pending authorization requests. Please try again la
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/0874719833cf73c7.
Report an issue: GitHub.