Repository navigation
Sentry Errors
Sentry throws SentryError for invalid configuration, local request
validation, and vendor responses — see errors/Base.ts
and errors/SentryErrorCodes.ts.
updateIssue()/createRelease() may also reject with a raw GuardianError
(as error.cause) when the request itself fails local schema validation
before any network call is made — see Schemas.
import { SentryError, SentryErrorCodes } from '@tundraconnect/sentry/errors';
const error = new SentryError('NOT_FOUND', { status: 404 });
console.log(error.message);
console.log(SentryErrorCodes.NOT_FOUND);Sentry's documented error envelope ({ detail, causes? }, see
Schemas) carries no machine-readable error code — only
free-text detail. These codes are therefore connect-specific, keyed off
the HTTP status Sentry actually returned
(https://docs.sentry.io/api/), plus configuration and local
request-validation failures that never come from the wire.
| Code | Meaning |
|---|---|
CONFIG_INVALID_TOKEN |
auth is missing, isn't type: 'BEARER', or its token is blank/not a string. |
CONFIG_INVALID_ORGANIZATION |
organization is missing, blank, or not a string. |
INVALID_REQUEST |
Local request validation failed (before a request was sent), or Sentry returned 400 Bad Request. |
AUTH_FAILED |
Sentry returned 401 Unauthorized. |
FORBIDDEN |
Sentry returned 403 Forbidden (token scope/permissions). |
NOT_FOUND |
Sentry returned 404 Not Found. |
RATE_LIMITED |
Sentry returned 429 Too Many Requests. |
RESPONSE_ERROR |
A success response's body failed schema validation. |
SERVICE_UNAVAILABLE |
A 5xx response, or any response whose body didn't parse. |
TIMEOUT |
Sentry did not answer within the client timeout (timeoutSeconds in context). |
NETWORK_ERROR |
fetch failed before any response (DNS, TLS, connection reset); the transport error is the cause. |
UNKNOWN_ERROR |
An unmapped status was returned, or an unknown code was supplied. |
The resolved code is also available as a public, readonly error.code
property — branch on failure mode without matching against .message:
if (error instanceof SentryError && error.code === 'RATE_LIMITED') {
// ...
}Use getContextValue() to read diagnostic metadata — never the token: this
connect never places auth.token into an error's context or message, so
error.message/error.toJSON() are always safe to log.
try {
await client.listIssues();
} catch (error) {
if (error instanceof SentryError) {
console.log(error.getContextValue('status'));
console.log(error.getContextValue('detail'));
}
}A 429 reads Sentry's documented rate-limit response headers
(https://docs.sentry.io/api/ratelimits/) into the thrown error's context —
rateLimitLimit, rateLimitRemaining, rateLimitReset (UTC seconds since
epoch when the window resets), rateLimitConcurrentLimit, and
rateLimitConcurrentRemaining. Sentry documents no Retry-After header for
this endpoint family.
try {
await client.listIssues();
} catch (error) {
if (error instanceof SentryError && error.code === 'RATE_LIMITED') {
const resetAt = error.getContextValue('rateLimitReset');
console.log(`Retry after ${resetAt}`);
}
}TIMEOUT, NETWORK_ERROR, SERVICE_UNAVAILABLE and RATE_LIMITED mean
"no answer yet": retrying later can help. Every other code is a definite
refusal or a misconfiguration that retrying will not fix. Branch on the
readonly err.transient, which is true for exactly these four, rather
than listing codes yourself. The set is also exported as
SENTRY_TRANSIENT_CODES from @tundraconnect/sentry/errors.
import { SentryError } from '@tundraconnect/sentry/errors';
declare function callTheClient(): Promise<unknown>;
try {
await callTheClient();
} catch (err) {
if (err instanceof SentryError && err.transient) {
// queue it and try again later
}
throw err;
}| Context | Present on | Meaning |
|---|---|---|
timeoutSeconds |
TIMEOUT |
The deadline that was missed, in seconds. |
A rate-limited request throws RATE_LIMITED. Two context values tell you what to
do next:
| Context | Meaning |
|---|---|
retryAfterSeconds |
Seconds the vendor asked you to wait, parsed by RESTler from Retry-After (delta seconds or an HTTP-date), X-RateLimit-Reset-After, RateLimit-Reset, or an epoch-seconds X-RateLimit-Reset. undefined when the response carried none — never a guess. |
retried |
Set only when maxRetryWait is configured: true if RESTler already waited once and was throttled again, false if it did not wait (the hint exceeded the cap, or there was no hint to wait on). |
Nothing is retried by default. Opt in with two client options (seconds,
each 0–120):
-
maxRetryWait— when a 429 carries a hint no longer than this, RESTler waits that long and retries once; otherwise it throwsRATE_LIMITEDimmediately.0disables the retry. -
defaultRetryWait— the wait used when a 429 carries no hint. Without it a hintless 429 is never retried: RESTler does not invent a delay. Only consulted whenmaxRetryWaitis set, and still capped by it.
- Algolia
- AzureBlob
- CloudflareDNS
- CloudflareEmail
- CloudflareSaaS
- CloudflareTurnstile
- CoinGecko
- Discord
- DodoPayments
- GCS
- GoogleAnalytics
- GoogleCertificateManager
- GoogleWebRisk
- Kalshi
- ntfy
- OpenExchange
- OpenWeatherMap
- PayPal
- Polymarket
- Razorpay
- Resend
- S3
- SendGrid
- Sentry
- Slack
- Stripe
- Telegram
- Twilio
- UpstashRedis
- URLhaus