Errors
Every failure the SDK raises extends SageSdkError and carries a code. That
is deliberate: matching on a code is stable, while matching on a message string
breaks the first time someone improves the wording.
The instanceof check is not optional. In TypeScript a caught value is
unknown, so reading error.code without narrowing first does not compile —
and the narrowing is what tells you the error came from the SDK rather than
from your own code or the network stack.
import { SageSdkError } from '@aephia/atlas-kit/client';
try { await sage.characters.forProfile(profileAddress);} catch (error) { if (error instanceof SageSdkError && error.code === 'ACCOUNT_NOT_FOUND') { // Handle the expected case. }}The codes worth knowing
Section titled “The codes worth knowing”ACCOUNT_NOT_FOUND — nothing exists at that address on this network.
Either the address is wrong, or the RPC is pointed at a different network. This
is the most common error, and the second cause is the one people miss.
INVALID_ACCOUNT_OWNER — something exists there, but it belongs to a
different program. The address is for something else entirely.
INVALID_DISCRIMINATOR — the account exists and belongs to SAGE, but it is
a different account type than this read expected.
INVALID_ENTITY_ID — the value is not a valid address.
MISSING_GAME_CONTEXT — a non-preset cluster was used without supplying a
Game address.
RELATIONSHIP_NOT_DISCOVERABLE — the relationship has no derivable address
and no discovery provider was configured. See identity for
the common case.
PROVIDER_ERROR — the RPC endpoint itself failed. Often rate limiting.
RESOURCE_LIMIT_EXCEEDED — a response exceeded a configured safety bound.
Absence is not an error
Section titled “Absence is not an error”Many reads have a maybe* form that returns undefined instead of throwing:
const standing = await maybeGetFactionStanding(ctx, profileAddress, factionId);The distinction is intent. Use get* when absence would be a bug in your
application, and maybe* when absence is an ordinary outcome. A profile with
no faction standing is not an error; a fleet address that resolves to nothing
probably is.
Invalid data never reaches the cache
Section titled “Invalid data never reaches the cache”Validation happens before decoding: program owner, discriminator, data shape, minimum length. Data that fails becomes a typed error and is never cached as valid state.
This is worth internalising, because the alternative is worse than it sounds. Without it, a truncated or mistaken RPC response becomes a plausible-looking value deep inside your application, and the bug surfaces somewhere unrelated, much later.
Reference
Section titled “Reference”client— the error types- The bindings escape hatch — where these guarantees stop