Errors
The SDK throws three distinct error classes. They are exhaustive — any
exception you catch from an ApyxClient either belongs to one of these
or is a viem / RPC-level error passed through unmodified.
import {
UnsupportedChainError,
WalletClientRequiredError,
InvalidAddressError,
} from '@koed_jang/apyx-sdk';
UnsupportedChainError
Thrown by: createApyxClient, getAddresses(chainId).
When: the chain.id you passed isn’t in the built-in
APYX_ADDRESSES registry.
Message:
chainId <id> is not supported by @apyx-labs/sdk
How to recover:
-
Pass a supported chain (
mainnet,base). -
Or, if you’ve redeployed the contracts to a new chain, override
addressesat construction:createApyxClient({ chain: someOtherChain, transport: http(), addresses: { apxUSD: '0x…', apyUSD: '0x…', apyUSDRateView: '0x…', // optional }, });Note that
addressesis aPartial<ApyxAddresses>, but if the chain isn’t in the built-in registry there’s nothing to merge with — you must supply the full triple (or omitapyUSDRateViewif it isn’t deployed there).
WalletClientRequiredError
Thrown by: any write method on apxUSD or apyUSD —
approve, transfer, permit, deposit, mint, withdraw, redeem.
When: you constructed the client without account, so no
walletClient was created, then called a method that needs one.
Message:
apxUSD.approve requires a wallet client. Pass `account` when calling createApyxClient.
(The leading apxUSD.approve is the action — it changes per call site
so log lines pinpoint the specific method.)
How to recover:
Pass account at construction:
const apyx = createApyxClient({
chain: mainnet,
transport: http(),
account: privateKeyToAccount(process.env.PK as `0x${string}`),
});
If you want a single client that does both reads (no signing) and
sometimes-writes, that’s still the pattern — apyx.publicClient is
fine to use for reads even when walletClient is set. If you don’t
want write capability at all (e.g. a UI that explicitly forbids
unsigned tx attempts), this error is the runtime guard that catches
mis-wired components.
This error is thrown synchronously from inside the write method, before any RPC traffic — there’s no risk of constructing or sending a tx without a signer.
InvalidAddressError
Thrown by: createApyxClient.
When: any address — built-in or overridden — fails
viem.isAddress(value, { strict: true }). Strict mode requires:
0xprefix- Exactly 40 hex characters
- All lowercase or correctly EIP-55 mixed-case-checksummed
Message:
Invalid address for `addresses.apyUSD`: <bad value>
The leading addresses.apyUSD is the field — addresses.apxUSD,
addresses.apyUSD, addresses.apyUSDRateView are the only three
possible.
How to recover:
- Drop garbage characters and ensure exactly 42 chars (
0x+ 40 hex). - If you copied an address by hand, run it through
viem.getAddress(...)first to checksum it. - Or pass it all-lowercase:
'0x…'.toLowerCase()is also accepted.
After construction, apyx.addresses is always EIP-55 checksummed and
Object.freezed — you can pass any valid form in, but you read out a
canonical normalized form.
What’s not thrown by the SDK
The SDK is intentionally thin on top of viem. Anything that isn’t
domain-specific (RPC errors, contract reverts, gas estimation failures,
chain-id mismatches at submission time, replay protection) bubbles up
as a viem BaseError subclass. Catch those at the call site if you
need to: most consumers find the rich viem error chain (error.cause,
error.shortMessage, error.metaMessages) sufficient without further
SDK-level abstraction.