paperclipai/paperclip · error · GitHubWebhookRecoveryError
github_webhook_recovery_http
github_webhook_recovery_http
Error message
github_webhook_recovery_http
What it means
Thrown when GitHub returned a status code different from the expected one (200 by default, 202 for redelivery, 201 for installation token mint, 204 for token revoke). The error carries the HTTP status, an optional retryAfterMs parsed from Retry-After / x-ratelimit headers, and requestMayHaveBeenAccepted=true only for 5xx/408 on uncertain mutations.
Source
Thrown at server/src/services/chat-github-webhook-config.ts:364
authorization: `Bearer ${input.token}`,
"x-github-api-version": "2022-11-28",
...(input.body ? { "content-type": "application/json" } : {}),
},
...(input.body ? { body: input.body } : {}),
},
);
if (controller.signal.aborted) {
await response.body?.cancel().catch(() => undefined);
throw new GitHubWebhookRecoveryError(
"github_webhook_recovery_transport",
null,
null,
input.uncertainMutation === true,
);
}
if (response.status !== (input.expectedStatus ?? 200)) {
await response.body?.cancel().catch(() => undefined);
throw new GitHubWebhookRecoveryError(
"github_webhook_recovery_http",
response.status,
retryDelay(response.headers),
input.uncertainMutation === true &&
(response.status >= 500 || response.status === 408),
);
}
return input.project(response, controller.signal);
})(),
]);
} catch (error) {
if (error instanceof GitHubWebhookRecoveryError) throw error;
throw new GitHubWebhookRecoveryError(
"github_webhook_recovery_transport",
null,
null,
input.uncertainMutation === true,
);View on GitHub (pinned to 01ad858492)
Solutions
- Read e.statusCode and e.retryAfterMs: wait retryAfterMs before retrying on 429/403-with-ratelimit headers.
- On 401, mint a fresh App JWT — yours likely expired (60s–10min TTL); on 403 check App permissions and installation status.
- On 404, verify the delivery/installation still exists before retrying.
- On 5xx/408 during a redelivery, reconcile first (getGitHubAppWebhookDelivery) because the mutation may have been accepted.
- Back off and retry GETs with jitter; stop hammering if 429 persists.
Example fix
// before
await listGitHubAppWebhookDeliveries({ fetch, appToken }); // throws on 429
// after
try {
return await listGitHubAppWebhookDeliveries({ fetch, appToken });
} catch (e) {
if (e instanceof GitHubWebhookRecoveryError && e.code === "github_webhook_recovery_http" && e.statusCode === 429 && e.retryAfterMs) {
await sleep(e.retryAfterMs);
return await listGitHubAppWebhookDeliveries({ fetch, appToken });
}
throw e;
} Defensive patterns
Strategy: retry
Validate before calling
null
Type guard
function isHttpRecoveryError(e: unknown): e is GitHubWebhookRecoveryError & { statusCode: number; retryAfterMs: number | null } {
return e instanceof GitHubWebhookRecoveryError && e.code === "github_webhook_recovery_http";
} Try / catch
try {
await listGitHubAppWebhookDeliveries({ fetch, appToken });
} catch (e) {
if (e instanceof GitHubWebhookRecoveryError && e.code === "github_webhook_recovery_http") {
if (e.retryAfterMs) await sleep(e.retryAfterMs); // rate-limited: respect Retry-After / x-ratelimit-reset
else if (e.statusCode !== null && e.statusCode >= 500) await sleep(jitteredBackoff());
else throw e; // 401/403/404/422 need action, not retry
} else throw e;
} Prevention
- Refresh App JWTs before they expire (~10 min TTL)
- Track x-ratelimit-remaining yourself during bulk recovery loops
- Check App installation status before recovery runs
- Distinguish retryable (429/5xx/408) from actionable (401/403/404/422) statuses
When it happens
Trigger: 401/403 from an expired or wrong-scope App JWT; 404 from a deleted delivery or installation; 422 from a bad repository list in the token request; 429 rate limit (retryAfterMs set from x-ratelimit-reset); 5xx GitHub server errors; 408 request timeout; redelivery POST returning anything but 202.
Common situations: App JWT expired (JWTs live ~10 minutes); installation uninstalled; App lacking webhook read permissions; hitting the 15,000 req/hr App rate limit in recovery loops; GitHub incident causing 5xx.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- Anthropic Managed Agents request failed with HTTP ${response
- request_failed
- github_webhook_recovery_invalid_response
- github_webhook_recovery_transport
- GitHub webhook configuration is incomplete
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/12a6379299582e53.
Report an issue: GitHub.