Skip to main content
Practical “I hit X, what’s wrong” guide for the 1.0.0 SDK. Every recipe assumes you have an AmplifyClient constructed like this:
If you’re upgrading from 0.5.x, start with the migration guide — the public API has changed substantially.
Cause: Package isn’t installed, or it’s installed but TypeScript can’t resolve it.Fix:
There are no required peer dependencies — the SDK ships its own HTTP layer. You still need a wallet/RPC client (e.g. viem, wagmi, ethers) to submit the calldata returned by prepare / prepare, but those are your choice.If installation succeeds but the import still fails, see “Types resolve to any” below — it’s almost always a moduleResolution issue.
Cause: API key is missing, malformed, or wrong for the environment you’re hitting.The SDK sends the key as the x-api-key header on every request. The value comes from whatever you passed as apiKey in the constructor.Fix:
  1. Confirm the env var is loaded before constructing the client:
  1. Catch the error and inspect the response body — the backend usually says exactly what’s wrong:
  1. If you’re hitting a non-production environment, confirm the key was issued for that environment — production and staging keys are not interchangeable.
Cause: API key is valid, but the account associated with it doesn’t have access to the vault or operation you’re calling.Fix: Verify the vault is enabled for your API key. client.amplify.vaults.list() only returns vaults your key can see, so a 403 on prepare for a vault that doesn’t appear in list() is the expected behaviour — request access from your Paxos Labs contact.
Cause: Almost always a bad input. The most common offenders, in order:
  • Bad vaultAddress — must be 0x + 40 hex chars (the BoringVault contract address). Get it from client.amplify.vaults.list()deployments[].boringVaultAddress.
  • Wrong chainId — the vault isn’t deployed on that chain. Each VaultDto.deployments[] entry has its own chainId; pass the one that matches your wallet’s network.
  • depositAmount in human units instead of base unitsdepositAmount is a decimal string in base units. "1.5" USDC is wrong; "1500000" (1.5 USDC at 6 decimals) is right.
  • Missing userAddress — required even when to is also passed.
Fix:
Cause: wantAsset is not an asset this vault redeems to on this chain.A vault accepts deposits in one set of assets and pays out withdrawals in another. The withdrawable set is on each vault’s assets[] entry where withdrawable: true.Fix:
Panic 0x11 is an arithmetic underflow. On the withdraw path it has two distinct causes — fix the right one.Cause 1 — wrong approval spender. The single most common mistake is approving the vault address (the share token itself) as the spender. The spender must be the WithdrawQueue address from the same vault.Fix: Read vault.withdrawQueueAddress and pass that as the spender on a standard ERC-20 approve:
EIP-2612 permit is not supported for vault shares — client.core.authorization.detect with tokenAddress: vaultAddress returns method: 'approval' or method: 'already_approved'. There is no permit-signature path on the withdraw flow.Cause 2 — fee consumes the entire offer. When the offer-fee percentage plus the flat fee adds up to ≥ shareAmount, the post-fee math inside submitOrder underflows and panics. Common on small redemptions of vaults that carry a non-trivial flat fee.Fix: Call client.amplify.withdraw.calculateFee before prepare and bail out when feeAmount >= shareAmount:
Cause: The token doesn’t implement EIP-2612 (no permit, nonces, or DOMAIN_SEPARATOR), or it implements a non-standard variant the backend can’t match.The SDK returns method: 'approval' instead of throwing for tokens it knows can’t permit. A 422 here means the backend tried and got an unexpected result — fall back to a standard approve call.Fix:
Cause: The request exceeded requestOptions.timeoutInSeconds (default 60). Usually a transient network or backend slowness.Fix: Retry with backoff. Each method accepts a per-call requestOptions.maxRetries (default 2); set a higher cap when you control retry budget yourself:
Cause: For an Amplify vault, the depositor token, base token, and share token must all share the same number of decimals. The vault math collapses if they don’t, and an on-chain deposit will revert.Fix: Read decimals() from each token via viem (or your wallet client) and compare against the vault’s configured assets:
If they don’t match, you’ve picked the wrong vault for this asset — check client.amplify.vaults.listAssets({ filter: 'depositable=true' }) for valid pairings.
Cause: Almost always a missing/invalid API key or a filter that excludes everything.Fix:
  1. Call without a filter to see what your key has access to:
  1. If that’s empty, the key has zero vault access — see “401 Unauthorized” / “403 Forbidden”.
  2. If non-empty, narrow with a filter that matches the vault you want. AIP-160-style filters use AND and =:
Cause: tsconfig.json moduleResolution is set to node (the legacy CJS resolver) and can’t see the package’s exports map.Fix: Set moduleResolution to bundler (Vite/Next/most modern toolchains) or node16 / nodenext:
Then restart your TS server. import type { Amplify } from '@paxoslabs/amplify-sdk' should resolve to a namespace of DTOs.
The SDK draws a clean line between runtime and types:
Amplify is a type-only namespace re-export. Importing it as a value (import { Amplify }) works at runtime but is meaningless — there are no runtime properties on it. Use import type to make intent obvious and to let the bundler tree-shake it.
The 1.0.0 SDK is a clean break — initAmplifySDK, LogLevel, every flat function export (prepare, prepare, getVaultsByConfig, etc.), every typed error class, and all ABI/EIP-712 helpers are gone. Everything now hangs off AmplifyClient subclients, and the only error types are AmplifyError and AmplifyTimeoutError.See Migrating from 0.5.x for a function-by-function mapping.

Inspecting an AmplifyError

Every non-2xx response, network failure, and JSON parse error throws AmplifyError. The shape is small and stable:
body is unknown because the backend may return any JSON shape. Narrow defensively before reading fields off it — never destructure blind.

Getting help

If a request is failing in a way none of the recipes above explain, capture the full AmplifyError (including statusCode, body, and the request input that triggered it) and reach out to support@paxoslabs.com.