npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

suiclient-error-decoder

v1.1.0

Published

A comprehensive error decoder for Sui blockchain transactions with support for custom error codes

Readme

SuiClient Error Decoder

npm version License: MIT Sui Blockchain Move TypeScript

SuiClient Error Decoder is a robust error decoding toolkit for Sui blockchain developers. Intelligently parses Move abort codes, system errors, and transaction failures with zero dependencies. Features customizable error mappings, automatic error categorization, and Sui-specific pattern recognition to simplify debugging and improve user feedback in dApps.

npmjs.com/package/suiclient-error-decoder

Features

  • 🔍 Comprehensive Error Parsing: Handles Move abort codes, named errors, and system errors
  • 🎯 Custom Error Codes: Add your own project-specific error codes
  • 📊 Error Categorization: Categorizes errors into move_abort, transaction, sui_system, or unknown
  • 🔄 Updatable Defaults: Built-in Sui error codes that can be updated
  • 💡 Zero Dependencies: Lightweight and easy to integrate

Installation

npm install suiclient-error-decoder
# or
yarn add suiclient-error-decoder
# or
pnpm add suiclient-error-decoder

Quick Start

import { decodeSuiError, SuiClientErrorDecoder } from 'suiclient-error-decoder';

// Quick one-liner decoding
try {
  // Your Sui transaction code here
  await suiClient.executeTransactionBlock(/* ... */);
} catch (error) {
  const humanReadableError = decodeSuiError(error);
  console.error(humanReadableError);
  // Output: "Error Code 1001: Index out of bounds"
}

Usage Examples

1. Basic Setup and Usage

import { SuiClient } from "@mysten/sui/client";
import { Transaction } from "@mysten/sui/transactions";
import { SuiClientErrorDecoder } from 'suiclient-error-decoder';

// Initialize the decoder
const errorDecoder = new SuiClientErrorDecoder();
const suiClient = new SuiClient({ url: getFullnodeUrl("testnet") });

// Example: Decoding a transaction error
async function transferSui(recipientAddress: string, amount: number) {
  try {
    const txb = new Transaction();
    const [coin] = txb.splitCoins(txb.gas, [amount]);
    txb.transferObjects([coin], recipientAddress);
    
    const result = await suiClient.executeTransactionBlock({
      transactionBlock: txb,
      signer: keypair, // your keypair
    });
    
    console.log('Transfer successful:', result.digest);
  } catch (error) {
    // Raw error might be: "MoveAbort(0x2::coin, 0) at instruction 15"
    const decodedError = errorDecoder.parseError(error);
    
    console.error('Transaction failed:');
    console.error('- Code:', decodedError.code); // 0
    console.error('- Message:', decodedError.message); // "Error Code 0: Insufficient balance"
    console.error('- Category:', decodedError.category); // "move_abort"
    console.error('- Known Error:', decodedError.isKnownError); // true
  }
}

2. DeFi Pool Interaction with Custom Errors

// ...other imports
import { Transaction } from "@mysten/sui/transactions";
import { SuiClientErrorDecoder } from 'suiclient-error-decoder';

// Setup decoder with DeFi-specific error codes
const defiDecoder = new SuiClientErrorDecoder({
  customErrorCodes: {
    // Pool-specific errors
    100: "Pool does not exist",
    101: "Insufficient liquidity in pool",
    102: "Slippage tolerance exceeded",
    103: "Pool is paused for maintenance",
    104: "Invalid token pair",
    
    // Staking errors
    200: "Staking period not yet ended",
    201: "Rewards already claimed",
    202: "Minimum stake amount not met",
    203: "Unstaking cooldown period active",
  }
});

async function swapTokens(tokenA: string, tokenB: string, amountIn: number) {
  try {
    const txb = new Transaction();
    
    // Add your DeFi swap logic here
    txb.moveCall({
      target: '0x123::dex::swap',
      arguments: [
        txb.pure(tokenA),
        txb.pure(tokenB),
        txb.pure(amountIn)
      ],
      typeArguments: ['0x2::sui::SUI', '0x456::usdc::USDC']
    });
    
    const result = await suiClient.signAndExecuteTransactionBlock({
      transactionBlock: txb,
      signer: keypair,
      options: { showEffects: true }
    });
    
    return result;
  } catch (error) {
    const decoded = defiDecoder.parseError(error);
    
    // Handle specific DeFi errors
    if (decoded.code === 101) {
      throw new Error('Not enough liquidity in the pool. Try a smaller amount.');
    } else if (decoded.code === 102) {
      throw new Error('Price moved too much. Increase slippage tolerance.');
    } else {
      throw new Error(`Swap failed: ${decoded.message}`);
    }
  }
}

3. React Hook Integration

import { useState } from 'react';
import { Transaction } from "@mysten/sui/transactions";
import { useSignAndExecuteTransaction } from '@mysten/dapp-kit';
import { SuiClientErrorDecoder } from 'suiclient-error-decoder';

// Custom hook for error handling
function useErrorDecoder() {
  const decoder = new SuiClientErrorDecoder({
    customErrorCodes: {
      404: "NFT not found",
      405: "NFT already minted",
      406: "Mint limit exceeded",
    }
  });
  
  return decoder;
}

function MintNFTComponent() {
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState<string>('');
  const { mutateAsync: signAndExecute } = useSignAndExecuteTransaction();
  const errorDecoder = useErrorDecoder();

  const mintNFT = async () => {
    setIsLoading(true);
    setError('');
    
    try {
      const txb = new Transaction();
      txb.moveCall({
        target: '0x123::nft::mint',
        arguments: [txb.pure('My NFT Name')]
      });
      
      const result = await signAndExecute({
        transactionBlock: txb,
        options: { showEffects: true }
      });
      
      console.log('NFT minted successfully:', result.digest);
    } catch (rawError) {
      const decoded = errorDecoder.parseError(rawError);
      
      // Set user-friendly error message
      setError(decoded.message);
      
      // Log detailed error for debugging
      console.error('Mint failed:', {
        code: decoded.code,
        category: decoded.category,
        isKnown: decoded.isKnownError,
        original: decoded.originalError
      });
    } finally {
      setIsLoading(false);
    }
  };

  return (
    <div>
      <button onClick={mintNFT} disabled={isLoading}>
        {isLoading ? 'Minting...' : 'Mint NFT'}
      </button>
      {error && <div className="error">{error}</div>}
    </div>
  );
}

4. Advanced Error Handling with Categorization

// ...imports
import { Transaction } from "@mysten/sui/transactions";
import { SuiClientErrorDecoder } from 'suiclient-error-decoder';

const decoder = new SuiClientErrorDecoder();

async function handleComplexTransaction() {
  try {
    // Your complex transaction logic
    const txb = new Transaction();
    // ... transaction setup
    
    const result = await suiClient.executeTransactionBlock({
      transactionBlock: txb,
      signer: keypair
    });
    
    return result;
  } catch (error) {
    const decoded = decoder.parseError(error);
    
    // Handle different error categories
    switch (decoded.category) {
      case 'move_abort':
        console.error('Smart contract error:', decoded.message);
        // Maybe retry with different parameters
        break;
        
      case 'transaction':
        console.error('Transaction processing error:', decoded.message);
        // Maybe increase gas or check network
        break;
        
      case 'sui_system':
        console.error('Sui system error:', decoded.message);
        // Maybe retry after some time
        break;
        
      default:
        console.error('Unknown error occurred:', decoded.message);
        // Log for investigation
        break;
    }
    
    // Re-throw with user-friendly message
    throw new Error(decoded.message);
  }
}

5. Batch Transaction Error Handling

async function processBatchTransactions(transactions: TransactionBlock[]) {
  const decoder = new SuiClientErrorDecoder();
  const results = [];
  const errors = [];

  for (let i = 0; i < transactions.length; i++) {
    try {
      const result = await suiClient.executeTransactionBlock({
        transactionBlock: transactions[i],
        signer: keypair
      });
      
      results.push({ index: i, success: true, result });
    } catch (error) {
      const decoded = decoder.parseError(error);
      
      errors.push({
        index: i,
        success: false,
        error: {
          code: decoded.code,
          message: decoded.message,
          category: decoded.category,
          isKnown: decoded.isKnownError
        }
      });
      
      // Continue with next transaction instead of stopping
      console.warn(`Transaction ${i} failed: ${decoded.message}`);
    }
  }

  return { results, errors };
}

6. Error Monitoring and Analytics

import { SuiClientErrorDecoder } from 'suiclient-error-decoder';

class ErrorAnalytics {
  private decoder: SuiClientErrorDecoder;
  private errorCounts: Map<string, number> = new Map();

  constructor() {
    this.decoder = new SuiClientErrorDecoder();
  }

  async executeWithAnalytics(transactionFn: () => Promise<any>) {
    try {
      return await transactionFn();
    } catch (error) {
      const decoded = this.decoder.parseError(error);
      
      // Track error frequency
      const errorKey = `${decoded.category}:${decoded.code || 'unknown'}`;
      this.errorCounts.set(errorKey, (this.errorCounts.get(errorKey) || 0) + 1);
      
      // Send to analytics service
      this.sendToAnalytics({
        timestamp: Date.now(),
        errorCode: decoded.code,
        errorMessage: decoded.message,
        category: decoded.category,
        isKnownError: decoded.isKnownError
      });
      
      throw error; // Re-throw the original error
    }
  }

  private async sendToAnalytics(errorData: any) {
    // Send to your analytics service
    console.log('Error Analytics:', errorData);
  }

  getErrorStats() {
    return Object.fromEntries(this.errorCounts);
  }
}

// Usage
const analytics = new ErrorAnalytics();

await analytics.executeWithAnalytics(async () => {
  // Your transaction code
  return await performSuiTransaction();
});

console.log('Error statistics:', analytics.getErrorStats());

7. Testing Error Scenarios

import { SuiClientErrorDecoder } from 'suiclient-error-decoder';

describe('Error Handling Tests', () => {
  const decoder = new SuiClientErrorDecoder({
    customErrorCodes: {
      999: "Test error for unit testing"
    }
  });

  test('should handle insufficient gas error', () => {
    const mockError = new Error('InsufficientGas: Transaction needs more gas');
    const decoded = decoder.parseError(mockError);
    
    expect(decoded.category).toBe('sui_system');
    expect(decoded.isKnownError).toBe(true);
    expect(decoded.message).toContain('gas');
  });

  test('should handle custom error codes', () => {
    const mockError = new Error('MoveAbort(0x123, 999)');
    const decoded = decoder.parseError(mockError);
    
    expect(decoded.code).toBe(999);
    expect(decoded.message).toContain('Test error for unit testing');
    expect(decoded.isKnownError).toBe(true);
  });

  test('should handle unknown errors gracefully', () => {
    const mockError = new Error('Some unknown error');
    const decoded = decoder.parseError(mockError);
    
    expect(decoded.category).toBe('unknown');
    expect(decoded.isKnownError).toBe(false);
    expect(typeof decoded.message).toBe('string');
  });
});

API Reference

SuiClientErrorDecoder

Constructor

new SuiClientErrorDecoder(options?: {
  customErrorCodes?: Record<number, string>;
  customTransactionErrors?: Record<string, string>;
  includeDefaults?: boolean; // Default: true
})

Methods

  • parseError(error: any): ParsedError - The core method. Parses and categorizes an error into a ParsedError object.
  • decodeError(error: any): string - A convenience method that returns only the human-readable error message string.
  • addErrorCodes(codes: Record<number, string>): void - Adds or updates custom numeric error codes at runtime.
  • addTransactionErrors(errors: Record<string, string>): void - Adds or updates custom string-based transaction errors at runtime.
  • updateDefaultErrorCodes(defaultCodes: Record<number, string>): void - Replaces the built-in default codes, preserving any custom codes you've added.
  • updateDefaultTransactionErrors(defaultErrors: Record<string, string>): void - Replaces the built-in default transaction errors, preserving custom ones.
  • getErrorCodes(): Record<number, string> - Returns a copy of all numeric error codes currently in use (defaults + custom).
  • getTransactionErrors(): Record<string, string> - Returns a copy of all transaction errors currently in use.
  • getErrorMessage(code: number): string | null - Gets the message for a specific numeric error code.
  • getTransactionErrorMessage(errorType: string): string | null - Gets the message for a specific transaction error type.
  • isKnownErrorCode(code: number): boolean - Checks if a numeric error code is in the map.
  • isKnownTransactionError(errorType: string): boolean - Checks if a transaction error type is in the map.

ParsedError Object

interface ParsedError {
  code?: number;                    // Numeric error code (if available)
  errorType?: string;              // Transaction error type (if available)
  message: string;                 // Human-readable error message
  isKnownError: boolean;          // Whether error is recognized
  category: 'move_abort' | 'transaction' | 'sui_system' | 'unknown';
  originalError: any;             // Original error object for debugging
}

Utility Functions

// Quick error decoding without creating decoder instance
decodeSuiError(error: any, customCodes?: Record<number, string>, customTransactionErrors?: Record<string, string>): string

// Default decoder instance
import { defaultDecoder } from 'suiclient-error-decoder';

Error Categories

| Category | Description | Example Error Codes | |----------------|-------------------------------------------|---------------------| | move_abort | Errors from Move smart contracts | 1000-1999 | | sui_system | Sui node/system-level errors | 2000-2999 | | transaction | Transaction processing errors | String-based | | unknown | Unrecognized error patterns | N/A |

Best Practices

  1. Always handle errors: Wrap your Sui transactions in try-catch blocks
  2. Use specific error codes: Define custom error codes for your smart contracts
  3. Categorize handling: Handle different error categories appropriately
  4. Log for debugging: Keep original error objects for development debugging
  5. User-friendly messages: Show decoded messages to users, not raw errors

Contributing

Contributions are welcome! Please open an issue or submit a PR:

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/AmazingFeature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/AmazingFeature)
  5. Open a pull request

Support

For support, please open an issue on our GitHub repository