Error Codes & Messages
Jelli uses exactly the same error codes as Phantom but with enhanced error messages and additional debugging information to help developers build better dApps.
🎯 Error Code Reference
4001
User Rejected
User declined the request
User clicks "Cancel" or "Reject"
4100
Unauthorized
Wallet not connected or permission denied
Calling methods before connect()
-32000
Invalid Input
Missing or malformed parameters
Bad transaction data or missing fields
-32002
Resource Not Available
Wallet busy or network issues
Multiple simultaneous requests
-32003
Transaction Rejected
Invalid transaction format
Malformed transaction object
-32601
Method Not Found
Unsupported method called
Calling non-existent wallet methods
-32603
Internal Error
Something went wrong in Jelli
Unexpected wallet or network errors
📦 Error Object Structure
Standard Phantom-Compatible Format
{
code: -32003, // Error code (same as Phantom)
message: "Jelli does not recognize a valid transaction.", // Jelli-branded message
name: "TransactionRejectedError" // Error type name
}
Enhanced Jelli Format
{
code: -32003, // Phantom-compatible code
message: "Jelli does not recognize a valid transaction.",
name: "TransactionRejectedError",
// Jelli enhancements:
category: "TRANSACTION", // Error category
timestamp: "2025-01-22T20:15:30.123Z", // When error occurred
metadata: { // Additional context
transactionType: "legacy",
transactionSize: 245,
networkLatency: 1200
}
}
🛡️ Handling Errors Properly
Basic Error Handling
try {
const { signature } = await provider.signAndSendTransaction(transaction);
console.log('✅ Transaction successful:', signature);
} catch (error) {
console.error('❌ Transaction failed:', error.code, error.message);
// Handle specific errors
switch (error.code) {
case 4001:
showUserMessage("Transaction was cancelled");
break;
case 4100:
await provider.connect(); // Try reconnecting
break;
case -32003:
showUserMessage("Invalid transaction. Please try again.");
break;
default:
showUserMessage("Something went wrong. Please try again.");
}
}
Advanced Error Handling with Jelli Enhancements
try {
const result = await provider.signAndSendTransaction(transaction);
return result;
} catch (error) {
// Log enhanced error details for debugging
console.log('🔍 Error Details:', {
code: error.code,
message: error.message,
category: error.category,
timestamp: error.timestamp,
metadata: error.metadata
});
// User-friendly error handling
switch (error.code) {
case 4001:
return { success: false, reason: 'user_cancelled' };
case 4100:
return { success: false, reason: 'not_connected' };
case -32000:
return {
success: false,
reason: 'invalid_input',
details: 'Please check your transaction parameters'
};
case -32002:
return {
success: false,
reason: 'wallet_busy',
details: 'Please wait and try again'
};
case -32003:
return {
success: false,
reason: 'invalid_transaction',
details: error.metadata?.transactionType ?
`Invalid ${error.metadata.transactionType} transaction` :
'Transaction format not recognized'
};
default:
return {
success: false,
reason: 'unknown_error',
details: error.message
};
}
}
🚨 Common Error Scenarios
1. User Rejection (4001)
// User clicks "Cancel" in Jelli popup
try {
await provider.signAndSendTransaction(transaction);
} catch (error) {
if (error.code === 4001) {
console.log("User cancelled the transaction");
// Don't retry automatically - respect user choice
}
}
2. Wallet Not Connected (4100)
// Calling methods before connect()
try {
await provider.signTransaction(transaction);
} catch (error) {
if (error.code === 4100) {
console.log("Wallet not connected, attempting to connect...");
await provider.connect();
// Now retry the operation
}
}
3. Invalid Transaction (-32003)
// Missing required fields or malformed transaction
try {
const invalidTx = new Transaction(); // Missing instructions!
await provider.signAndSendTransaction(invalidTx);
} catch (error) {
if (error.code === -32003) {
console.log("Transaction is invalid:", error.message);
// Check: instructions, recent blockhash, fee payer
}
}
4. Resource Not Available (-32002)
// Multiple simultaneous requests
try {
// Don't do this - multiple concurrent requests
Promise.all([
provider.signAndSendTransaction(tx1),
provider.signAndSendTransaction(tx2)
]);
} catch (error) {
if (error.code === -32002) {
console.log("Wallet is busy, waiting...");
// Implement retry with backoff
await new Promise(resolve => setTimeout(resolve, 2000));
}
}
🔧 Error Prevention Best Practices
1. Always Check Connection
async function safeTransaction(transaction) {
// Check connection first
if (!provider.isConnected) {
await provider.connect();
}
return provider.signAndSendTransaction(transaction);
}
2. Validate Transactions
function validateTransaction(transaction) {
if (!transaction.recentBlockhash) {
throw new Error("Missing recent blockhash");
}
if (!transaction.feePayer) {
throw new Error("Missing fee payer");
}
if (transaction.instructions.length === 0) {
throw new Error("No instructions in transaction");
}
}
3. Implement Retry Logic
async function transactionWithRetry(transaction, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await provider.signAndSendTransaction(transaction);
} catch (error) {
if (error.code === 4001) {
throw error; // Don't retry user rejection
}
if (i === maxRetries - 1) {
throw error; // Last attempt failed
}
// Wait before retry
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
}
}
}
💡 Pro Tip: Jelli's enhanced error information helps you debug faster, but the core error codes remain identical to Phantom for seamless migration!
Last updated