SDK
SDK errors
Every error the SDK throws is an OortError subclass. Branch on code first, then on reason, and retry only what says retryable.
What an error carries
| Field | What it is |
|---|---|
code | One of ten codes, the same the CLI's --json output uses. |
reason | A finer, stable string, when there is one. |
fix | A runnable oort command that fixes it, or null. |
retryable | True when the same call can succeed later. |
retryAfter | Seconds to wait, when Oort Cloud sent Retry-After. |
status | The HTTP status, for an Oort Cloud refusal. |
message | One line for people. It names fields, never their values, and never carries a key. |
OortNeedsKeyError also has role (embed, rerank, decide or write) and envVar, the environment variable that would supply the key. A model vendor's own error is reported by its class name only.
Codes and reasons
OortUsageError- code
usage - Typical reason
invalid-argument,principal-required,self-not-derivable,user-missing,closed,embedder-mismatch(fixoort reembed),bad-request,too-large OortNotFoundError- code
not-found - Typical reasonnone
OortAmbiguousIdError- code
ambiguous-id - Typical reasonnone
OortNeedsKeyError- code
needs-key - Typical reason
missing-key(fixoort models pulloroort keys set) OortNeedsLoginError- code
needs-login - Typical reason
no-key,key-rejected(fixoort login) OortNeedsConfirmationError- code
needs-confirmation - Typical reason
preview-required,findings-unacknowledged OortCloudOnlyError- code
cloud-only - Typical reason
hive-level, orforgetwitheverywherein local mode OortNetworkError- code
network - Typical reason
unreachable,timeout,busy. Always retryable. OortRefusedError- code
refused - Typical reason
scope-denied,forbidden,star-in-cloud,star-with-user,local-only,experts-not-listed,not-an-expert,daily-limit,cap-unavailable(retryable),expert-only,not-current,payment-required,not-enabled,hive-not-enabled,rate-limit(retryable),migration-required(fixoort doctor) OortInternalError- code
internal - Typical reason
store-busy(retryable), else none
New reason strings may appear in any release, so branch on code first and treat an unknown reason like its code.
Handle them
Retry what is retryable, waiting retryAfter when it is set. Then branch on code, and show reason and fix:
import { createOort, OortError } from 'oortmem';
/** Retries what Oort marks `retryable`, waiting `retryAfter` seconds when the service sent it. */
async function withRetry<T>(fn: () => Promise<T>, tries = 3): Promise<T> {
for (let attempt = 1; ; attempt++) {
try {
return await fn();
} catch (e) {
if (!(e instanceof OortError) || !e.retryable || attempt >= tries) throw e;
await new Promise((done) => setTimeout(done, (e.retryAfter ?? attempt) * 1000));
}
}
}
try {
await using oort = await createOort({ mode: 'cloud', keySources: ['env'] });
const r = await withRetry(() =>
oort.observe({ user: 'Our staging database runs on port 6543.', assistant: 'Noted.' }),
);
console.log('saved:', r.outcome);
} catch (e) {
if (!(e instanceof OortError)) throw e;
// Branch on `code` first: new `reason` strings may appear in any release.
switch (e.code) {
case 'needs-login':
console.error(`No usable Oort key (${e.reason}). Fix: ${e.fix}`);
break;
case 'refused':
console.error(`Refused (${e.reason}): ${e.message}`);
break;
case 'network':
console.error(`Oort Cloud is unreachable (${e.reason}); try again later.`);
break;
default:
throw e;
}
}Retry
These are retryable, and nothing else is:
- Every
OortNetworkError:unreachable,timeoutandbusy. rate-limitandcap-unavailable(OortRefusedError).store-busy(OortInternalError): another process held the local store's lock.
Wait retryAfter seconds when it is set. In cloud mode, retry observe with the same turnRef: Oort Cloud saves the turn once and answers duplicate: true. Local mode does not deduplicate, so a retried observe may write twice. The serverless example passes the request id as turnRef.
An aborted signal stops the SDK waiting and rejects with the signal's reason. Work already sent (cloud) or started (local) may still land, so retry it with the same turnRef.
Limits
Anything over a limit throws OortUsageError before any I/O. The error names the field, never its value.
| Input | Limit |
|---|---|
| recall query | 2,048 UTF-8 bytes |
recall limit | 1 to 50 |
| observe turn | 128 KiB in all (the engine keeps 32 KiB of text after scrubbing) |
tools summaries in a turn | Truncated to 16 × 512 bytes, never refused |
turnRef | 128 characters |
remember | 5 facts of at most 500 characters |
recent limit | 1 to 100 |
| Judgment fields | As oort judge record: subject 500 characters, reason 2,000 |
Every method and its result is in the API reference.