Algolia Errors - TundraSoft/tundra-connect GitHub Wiki
Algolia Errors
Algolia throws AlgoliaError for local request/config validation and
for every vendor response — see errors/Base.ts and
errors/AlgoliaErrorCodes.ts.
import { AlgoliaError, AlgoliaErrorCodes } from '@tundraconnect/algolia/errors';
const error = new AlgoliaError('SERVICE_UNAVAILABLE', { status: 503 });
console.log(error.message);
Codes
Algolia's error envelope is a single documented shape —
{"message":"Invalid Application-ID or API key","status":403} — with no
separate vendor error code to key off, so every vendor-response code below
is dispatched purely on HTTP status (see Algolia.ts's __toError).
| Code | Meaning |
|---|---|
UNKNOWN_ERROR |
An unmapped status was returned, or an unknown code was supplied. |
INVALID_REQUEST |
HTTP 400/422, or a local Guardian validation failure before the request was sent. |
RESPONSE_ERROR |
A success response's body failed schema validation. |
SERVICE_UNAVAILABLE |
HTTP 5xx. |
TIMEOUT |
No complete answer within the timeout (context timeoutSeconds). |
NETWORK_ERROR |
The request failed before any response (DNS, TLS, connection reset). |
AUTH_FAILED |
HTTP 401/403 — invalid applicationId/apiKey, or a key missing the required ACL. |
NOT_FOUND |
HTTP 404 — the index, object, or task does not exist. |
RATE_LIMITED |
HTTP 429 — too many requests for the configured plan/quota. |
CONFIG_INVALID_AUTH |
auth is missing or not { type: 'CUSTOM', ... }. |
CONFIG_INVALID_APPLICATION_ID |
auth.applicationId is missing or empty. |
CONFIG_INVALID_API_KEY |
auth.apiKey is missing or empty. Never echoes the (invalid) value. |
TASK_TIMEOUT |
waitTask exceeded its polling budget without observing status: 'published'. |
TIMEOUT, NETWORK_ERROR, SERVICE_UNAVAILABLE and RATE_LIMITED are
transient: Algolia gave no definite answer, so the same call may
succeed later. err.transient is true for exactly these and false for
every other code (a definite refusal or a misconfiguration retrying won't
fix). The set is also exported as ALGOLIA_TRANSIENT_CODES from
@tundraconnect/algolia/errors.
INVALID_REQUEST is intentionally reused for both a local (pre-request)
validation failure and a vendor 400/422 response — both mean "the request
itself was rejected as invalid," just at different points in the request
lifecycle. The vendor's message (when available) is preserved via
getContextValue('message').
The resolved code is also available as a public, readonly error.code
property — branch on failure mode without matching against .message:
if (error instanceof AlgoliaError && error.code === 'RATE_LIMITED') {
// back off and retry
}
Use getContextValue() to read diagnostic metadata — see
errors/Base.ts. context.applicationId may
legitimately appear in a thrown error (it's not a credential);
context.apiKey never does — see the "Credentials" section below.
Credentials never leak
Algolia sends two credential-shaped headers on every request:
x-algolia-application-id (not secret) and x-algolia-api-key (secret).
Algolia overrides _isSensitiveHeader so x-algolia-api-key is redacted
as [REDACTED] in call/authFailure event payloads and in any thrown
error's request context — the same class of bug this repo's adversarial
review already found and fixed once in CoinGecko's vendor-specific API-key
header. x-algolia-application-id is deliberately not redacted: it
isn't a credential, and legitimately shows up in logs, error contexts, and
even the request URL's hostname.
auth.apiKey is also never placed in a thrown config error's context —
CONFIG_INVALID_API_KEY is thrown with no apiKey field at all, not even
the invalid value, so no future refactor can start echoing it unnoticed.
Backing off after a 429
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.