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

Code
Name
Description
When It Occurs

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