plugin-retry.js

Adds automatic, configurable retry handling to Octokit's GitHub API requests.

Library
npm
v8.1.1
48stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
61/100Good
Development Activity72
Maintenance72
Community28
Maturity60
Momentum12

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
72/100Good
Architecture75
Code Quality78
Innovation55
Learning Curve80

@octokit/plugin-retry is an official Octokit plugin that wraps every outgoing request with automatic retry logic. When a request fails with a server error or a retryable 4xx/5xx status, the plugin schedules a retry with exponential backoff instead of surfacing the failure immediately, which smooths over transient GitHub API instability and secondary rate limits without any extra code in the calling application.

Under the hood it hooks into Octokit’s request and error lifecycle events using bottleneck as a lightweight scheduler, tracks a retry count and backoff delay on the request object, and re-throws once the configured retry budget is exhausted. Consumers install it by composing it onto an Octokit class (Octokit.plugin(retry)) and can tune behavior — enabling/disabling the plugin, the base backoff value, the retry count, and which status codes should never be retried — through a single retry option block.

What You Get

  • Automatic retries for server errors and retryable 4xx/5xx responses, skipping ones that should never be retried (400, 401, 403, 404, 410, 422, 451) by default
  • Exponential backoff between attempts, computed from the retry count and a configurable base delay
  • Per-request overrides via request: { retries, retryAfter } that bypass the default do-not-retry list entirely
  • GraphQL-aware handling that detects GitHub’s transient ‘Something went wrong while executing your query’ error and retries it like a 500
  • A simple on/off switch (retry: { enabled: false }) to disable the plugin for a given Octokit instance

Common Use Cases

  • Hardening CI/CD bots and GitHub Apps against transient GitHub API 5xx errors and abuse-rate-limit responses
  • Building GitHub integrations that need resilient long-running sync jobs (issue/PR mirrors, backup tools) without manual retry code
  • Wrapping GraphQL calls to GitHub’s API so intermittent query execution errors don’t fail an entire job
  • Tuning retry aggressiveness per-request for expensive or rate-limit-sensitive endpoints while leaving defaults elsewhere

Under The Hood

Architecture The plugin’s retry() entry point (src/index.ts) merges a default RetryState with any octokitOptions.retry overrides, builds a retryPlugin object exposing retry.retryRequest, and — if enabled — registers two Octokit lifecycle hooks: octokit.hook.error("request", ...) and octokit.hook.wrap("request", ...). errorRequest (src/error-request.ts) inspects a failed request’s status against the configurable doNotRetry list, computes a backoff value, and either re-throws the original error or an augmented one carrying retry metadata. wrapRequest (src/wrap-request.ts) creates a per-request Bottleneck limiter, listens for its failed event to read that retry metadata and return a millisecond delay, and additionally detects GitHub GraphQL’s transient “Something went wrong while executing your query” error inside successful HTTP responses, converting it into a synthetic RequestError fed back through errorRequest so REST and GraphQL failures share one retry path.

Tech Stack A TypeScript, ESM-only (type: module) package targeting Node >=20 with conditional exports, requiring consumers on moduleResolution: node16. It peer-depends on @octokit/core (>=7) and depends on @octokit/request-error, @octokit/types, and bottleneck for scheduling. Builds run through a custom scripts/build.mjs plus tsc for declaration files; tests run on Vitest with V8 coverage; Prettier enforces formatting as part of pretest; releases are fully automated via semantic-release (commit-analyzer, release-notes-generator, npm, GitHub plugins), and CI includes a CodeQL security-analysis workflow.

Code Quality Tests in test/retry.test.ts and test/smoke.test.ts exercise the plugin through a TestOctokit composed from a mock-response plugin plus the real retry plugin (test/octokit.ts), asserting on request logs and timings rather than mocking internals directly — a reasonably thorough black-box style for a package this size. Source is fully typed, with explicit RetryOptions/RetryState/RetryPlugin interfaces and a satisfies assertion validating the default state at compile time. Error handling is explicit: isRequestError narrows unknown errors, and unrecognized errors are re-thrown immediately rather than swallowed.

API Design The public surface is minimal and idiomatic for the Octokit plugin ecosystem — consumers compose it once (Octokit.plugin(retry)) and get sensible defaults with zero required configuration, with per-request overrides available for edge cases. The standout design choice is bridging GraphQL’s in-body error convention into the same retry path as REST status-code errors, letting one mechanism cover both APIs. The underlying retry/backoff technique itself is a well-understood pattern rather than a novel algorithm, so this reads as solid, well-executed developer experience rather than groundbreaking design.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search