Guides

Handle errors and rate limits

Catch typed errors, and see how providers retry rate-limited requests.

Failed requests reject with a typed error. All of them extend ForgeError, so you can catch the base class and narrow with instanceof:

import { ForgeError, RateLimitedError, TokenRevokedError } from 'forges'

try {
  await gh.threads.close(thread.ref)
}
catch (error) {
  if (error instanceof RateLimitedError) {
    console.warn(`Rate limited until ${error.resetAt?.toISOString()}`)
  }
  else if (error instanceof TokenRevokedError) {
    await askForNewToken()
  }
  else if (error instanceof ForgeError) {
    console.error(error.forge, error.url, error.message)
  }
  else {
    throw error
  }
}

Errors carry forge, instance, url and method when the failure came from a request. ForgeApiError and its subclasses also have status and a truncated body. The error reference lists every class.

Rate limits

When a forge rate-limits a request and sets retry-after to one minute or less, the provider waits that long and retries once. Pass onRetry to log or count these retries. It receives the url, the method and the wait in milliseconds:

const forge = github({
  auth,
  onRetry: ({ method, url, wait }) =>
    console.warn(`Retrying ${method} ${url} in ${wait} ms`),
}).create()

A longer wait, or a second limit, rejects with RateLimitedError. resetAt tells you when the limit resets, and secondary is true for an abuse limit that has no request counter.

After a listing, page.rateLimit reports the budget the forge sent with the response.

Unsupported operations

Calling an operation that the forge lacks rejects with UnsupportedOperationError. Avoid it with can().

Warnings

Some problems don't fail a call. A listing can skip an item it couldn't read, or ignore a filter that the forge lacks. The provider reports these as warnings with a stable code, such as filter_unsupported or thread_unreadable.

Read warnings on a page, or on an iterable during or after iteration:

const threads = gh.threads.list(repo, { sort: 'comments' })

for await (const thread of threads) {
  render(thread)
}

for (const warning of threads.warnings) {
  console.warn(warning.code, warning.message)
}

Timeouts

A request that exceeds the provider's timeout rejects with ForgeTimeoutError. A request that gets no response, for example because of DNS or TLS failures, rejects with ForgeNetworkError.

Copyright © 2026