grepticon/

Error handling

The SDK's dual error model and automatic 429 retries.

The SDK has two error models, and which one applies depends on the call:

  • Management calls on client.workspaces, client.files, client.tokens, and client.audit throw GrepticonError on any non-2xx response. Wrap them in try / 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 on not_found / bad_request. The text is the message 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 result and try again. Your management automation, by contrast, 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, like 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';
}
statusMeaning
'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 message 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 a tool-level 404 or 400 becomes an envelope, with status not_found or bad_request. 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 429 twice, honoring Retry-After before surfacing the error.
  • Only 429 is retried. Other 4xx and all 5xx responses are not retried; management calls throw and reads return their envelope 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 429

RetryOption is false | { retries?: number }. When retries are exhausted, a management call throws GrepticonError with status: 429, and a read throws the same, since 429 is not one of the envelope statuses.

Where to go next

On this page