Documentation Index
Fetch the complete documentation index at: https://docs.cavos.xyz/llms.txt
Use this file to discover all available pages before exploring further.
Error Classes
JwtExpiredError
Thrown by execute() when the OAuth JWT has expired and the session is not yet registered on-chain. The user must re-authenticate.
import { JwtExpiredError } from '@cavos/react';
try {
await execute(calls);
} catch (err) {
if (err instanceof JwtExpiredError) {
// Prompt re-login
await login('google');
}
}
JWTs from Google/Apple typically expire after 1 hour. Once the session key is registered on-chain (first transaction), subsequent transactions use the session key directly — no JWT needed until the session itself expires.
Authentication Errors
OAuth Login Cancelled or Blocked
try {
await login('google');
} catch (error) {
if (error.message.includes('closed without completing')) {
showMessage('Login window was closed. Please try again.');
} else if (error.message.includes('timed out')) {
showMessage('Login timed out. Please try again.');
}
}
Nonce Mismatch
Happens if session state was corrupted between the OAuth redirect and the callback:
try {
await login('google');
} catch (error) {
if (error.message.includes('nonce')) {
// Clear any stale state and retry
sessionStorage.clear();
await login('google');
}
}
Session Errors
Session Not Registered
Thrown when execute() is called with gasless: false before any on-chain session exists:
try {
await execute(calls, { gasless: false });
} catch (error) {
if (error.message.includes('non-sponsored transaction without a registered session')) {
// Execute one sponsored tx first — it registers the session automatically
await execute(calls); // gasless: true (default)
// Now retry with user-pays
}
}
Session Expired (Beyond Grace Period)
try {
await execute(calls);
} catch (error) {
if (error.message.includes('SESSION_EXPIRED')) {
// Session expired beyond the 48h grace window — must re-login
await login('google');
}
}
Session Expired (Within Grace Period)
The SDK handles this automatically — execute() will call renewSession() internally before proceeding. You don’t need to handle this case explicitly.
Wallet Not Initialized
try {
await execute(calls);
} catch (error) {
if (error.message.includes('not initialized') || error.message.includes('Please login')) {
await login('google');
}
}
Transaction Errors
Session Policy Violation
try {
await execute(calls);
} catch (error) {
if (error.message.includes('Spending limit exceeded')) {
showMessage('This transaction exceeds your session spending limit.');
} else if (error.message.includes('not in allowedContracts') || error.message.includes('policy')) {
showMessage('This contract is not permitted by your session policy.');
}
}
Paymaster Error
try {
await execute(calls);
} catch (error) {
if (error.message.includes('paymaster') || error.message.includes('gas tank')) {
showMessage('Gasless sponsorship is temporarily unavailable. Try again shortly.');
}
}
Insufficient Balance (User-Pays)
try {
await execute(calls, { gasless: false });
} catch (error) {
if (error.message.includes('insufficient') || error.message.includes('max_fee')) {
showMessage('Insufficient STRK balance for transaction fee.');
}
}
Contract / Entrypoint Not Found
try {
await execute(calls);
} catch (error) {
if (error.message.includes('Contract not found')) {
showMessage('Contract does not exist on this network.');
} else if (error.message.includes('Entry point not found')) {
showMessage('Function does not exist on this contract.');
}
}
Wallet Errors
Account Not Deployed
try {
await execute(calls);
} catch (error) {
if (error.message.includes('not deployed')) {
// Deployment normally happens automatically — trigger manually if needed
await deployAccount();
await execute(calls);
}
}
Address Seed Mismatch
Happens when the identity (sub) or app salt doesn’t match what the wallet was created with:
try {
await login('google');
} catch (error) {
if (error.message.includes('Address seed mismatch')) {
// Identity verification failed — clear state and re-authenticate
await logout();
await login('google');
}
}
MAU Limit Exceeded
try {
await login('google');
} catch (error) {
if (error.message.includes('MAU limit')) {
showMessage('App has reached its monthly active user limit.');
}
}
Network Errors
RPC Timeout or Rate Limit
try {
await execute(calls);
} catch (error) {
if (error.message.includes('timeout') || error.message.includes('network')) {
showMessage('Network error. Please check your connection and try again.');
}
}
To avoid rate limits on the default shared RPC, provide your own:
<CavosProvider config={{
appId: 'your-app-id',
starknetRpcUrl: 'https://your-own-rpc-node.com',
}}>
Debugging
Enable Logging
<CavosProvider config={{
appId: 'your-app-id',
enableLogging: true,
}}>
Inspect Wallet State
const { isAuthenticated, address, walletStatus, sessionPublicKey } = useCavos();
console.log({
isAuthenticated,
address,
sessionPublicKey,
walletStatus, // { isDeploying, isDeployed, isRegistering, isSessionActive, isReady, pendingDeployTxHash? }
});
Error Recovery Reference
| Error | Cause | Recovery |
|---|
JwtExpiredError | OAuth JWT expired before session was registered | Re-login via login() |
SESSION_EXPIRED | Session expired past 48h grace window | Re-login via login() |
non-sponsored transaction without a registered session | gasless: false before first tx | Execute a sponsored tx first |
Spending limit exceeded | Transaction exceeds session policy limit | Check spendingLimits in policy |
Address seed mismatch | Identity/salt mismatch | Logout and re-login |
MAU limit | App exceeded monthly users | Upgrade plan or wait for reset |
paymaster / gas tank | Paymaster temporarily unavailable | Retry, or use gasless: false |
not initialized | execute() called before login() | Call login() first |
timeout | RPC timeout | Retry, or configure a custom RPC URL |