Error handling
The SDK's dual error model — management calls throw GrepticonError, read tools return a { text, status } envelope — plus 429 retries.
The SDK has two error models, and which one applies depends on the call:
- Management calls — everything on
client.workspaces,client.files,client.tokens, andclient.audit— throwGrepticonErroron any non-2xx response. Wrap them intry/catch. - Read tools —
client.session(ws).ls/.find/.cat/.grep(and the AI-SDK adapter that wraps them) — return a{ text, status }envelope and do not throw onnot_found/bad_request. Thetextis steering guidance the agent reads and acts on, so a missing file is a normal result, not an exception.
This split is deliberate: an agent looping over tools should never crash on a typo'd path — it should read the steering text and try again — while your management automation wants a hard failure it can catch.
Management calls: GrepticonError
Any non-2xx from a management call throws a GrepticonError:
class GrepticonError extends Error {
readonly status: number; // the HTTP status
message: string; // the server's actionable sentence
}status is the HTTP status code and message is the server's relayable
sentence (for example, the free-plan workspace-quota message, or "Access tokens
are read-only…"). Catch it to branch on status:
import { GrepticonError, GrepticonClient } from '@grepticon/sdk';
const client = new GrepticonClient({
apiKey: process.env.GREPTICON_API_KEY ?? '',
});
try {
await client.workspaces.create('handbook');
} catch (err) {
if (err instanceof GrepticonError) {
console.error(`Grepticon API error ${err.status}: ${err.message}`);
} else {
throw err;
}
}Read tools: the { text, status } envelope
Session reads resolve to a ToolEnvelope — never a throw for a tool-level miss:
interface ToolEnvelope {
text: string;
status: 'ok' | 'not_found' | 'bad_request';
}status | Meaning |
|---|---|
'ok' | The read succeeded; text is the result. |
'not_found' | Path or match didn't exist (or isn't visible to the token). |
'bad_request' | The tool arguments were invalid. |
text always holds a message worth surfacing to the model — for not_found /
bad_request it's the steering sentence telling the agent what to try next. The
AI-SDK adapter forwards text straight to the model and ignores
status; when you call a session directly you can branch on status yourself.
const session = client.session('handbook');
const result = await session.cat({ path: 'guides/onboarding.md' });
if (result.status === 'ok') {
console.log(result.text);
} else {
console.warn(`read ${result.status}: ${result.text}`);
}Only tool-level 404 (not_found) and 400 (bad_request) become envelopes.
Auth failures (401 / 403), rate limits (429 after retries), and server
errors (5xx) on a read still throw GrepticonError — a bad key or an
outage is not something an agent should paper over with a retry.
waitForReady throws only on timeout
files.waitForReady is the exception to the
management-throw rule: it does not throw when a file fails to ingest. A file
that ends in status: 'error' is a settled, resolved result — waitForReady
returns it. It throws (a plain Error, not a GrepticonError) only when it
times out before every targeted path settles. So always inspect the returned
entries:
const [file] = await client.files.waitForReady('handbook', {
paths: ['guides/onboarding.md'],
});
if (file?.status === 'error') {
throw new Error(`Ingestion failed: ${file.errorDetail ?? 'unknown error'}`);
}Rate limits & automatic 429 retries
Reads are rate-limited per credential and per account. A throttled
request returns 429 Too Many Requests with a Retry-After header. The
client handles this for you:
- By default it retries a
429twice, honoringRetry-After(bounded to a 1–10 second wait) before surfacing the error. - Only
429is retried. Other 4xx and all 5xx responses are not retried — they throw (management) or return their envelope (reads) immediately.
Tune the budget — or opt out entirely — with the retry option:
new GrepticonClient({ apiKey, retry: { retries: 5 } }); // retry up to 5 times
new GrepticonClient({ apiKey, retry: false }); // never retry; surface the 429RetryOption is false | { retries?: number }. When retries are exhausted, a
management call throws GrepticonError with status: 429, and a read throws the
same (429 is not one of the envelope statuses).
Where to go next
- SDK reference — the full client surface these errors come from.
- AI-SDK adapter — how the envelope reaches the model.
- Limits — the rate-limit windows behind the
429s.