Complete reference for error codes, messages, and troubleshooting in the BSV TypeScript SDK.
Code: INSUFFICIENT_FUNDS
Message: “Insufficient funds to create transaction”
Cause: Wallet doesn’t have enough UTXOs to cover transaction outputs and fees
Solutions:
listOutputs()
Code: INVALID_TRANSACTION
Message: “Transaction validation failed”
Cause: Transaction structure or signatures are invalid
Solutions:
Code: TRANSACTION_TOO_LARGE
Message: “Transaction exceeds maximum size limit”
Cause: Transaction size exceeds network limits
Solutions:
Code: INVALID_SCRIPT
Message: “Script execution failed”
Cause: Locking or unlocking script contains errors
Solutions:
Script.fromASM()
Code: WALLET_NOT_CONNECTED
Message: “Wallet connection not established”
Cause: WalletClient not connected to substrate
Solutions:
await wallet.connectToSubstrate()
Code: AUTHENTICATION_FAILED
Message: “Wallet authentication failed”
Cause: User denied access or authentication expired
Solutions:
Code: WALLET_LOCKED
Message: “Wallet is locked or requires password”
Cause: Wallet requires user authentication
Solutions:
Code: ACTION_REJECTED
Message: “User rejected the transaction”
Cause: User declined transaction in wallet UI
Solutions:
Code: NETWORK_ERROR
Message: “Network request failed”
Cause: Connection issues with blockchain nodes
Solutions:
Code: NODE_UNAVAILABLE
Message: “Blockchain node is unavailable”
Cause: Target node is down or unreachable
Solutions:
Code: BROADCAST_FAILED
Message: “Transaction broadcast failed”
Cause: Network rejected transaction or broadcast error
Solutions:
Code: TIMEOUT_ERROR
Message: “Request timeout exceeded”
Cause: Network request took too long
Solutions:
Code: INVALID_PRIVATE_KEY
Message: “Private key is invalid or out of range”
Cause: Private key doesn’t meet secp256k1 requirements
Solutions:
PrivateKey.fromRandom()
Code: INVALID_PUBLIC_KEY
Message: “Public key is invalid or not on curve”
Cause: Public key point is invalid
Solutions:
PublicKey.fromPrivateKey()
for generationCode: SIGNATURE_VERIFICATION_FAILED
Message: “Digital signature verification failed”
Cause: Signature doesn’t match message and public key
Solutions:
Code: ENCRYPTION_FAILED
Message: “Symmetric encryption operation failed”
Cause: AES encryption/decryption error
Solutions:
Code: INVALID_MERKLE_PROOF
Message: “Merkle proof verification failed”
Cause: Merkle path doesn’t lead to valid root
Solutions:
Code: BLOCK_HEADER_INVALID
Message: “Block header validation failed”
Cause: Block header doesn’t meet consensus rules
Solutions:
Code: CHAIN_VALIDATION_FAILED
Message: “Blockchain validation failed”
Cause: Chain doesn’t follow consensus rules
Solutions:
Code: INVALID_CONFIG
Message: “SDK configuration is invalid”
Cause: Configuration parameters are incorrect
Solutions:
Code: UNSUPPORTED_NETWORK
Message: “Network type is not supported”
Cause: Invalid network specification
Solutions:
All SDK errors implement the WalletErrorObject
interface:
interface WalletErrorObject {
code: string
description: string
stack?: string
context?: Record<string, any>
}
try {
const result = await wallet.createAction({
description: 'Test transaction',
outputs: [{
satoshis: 100,
lockingScript: Script.fromASM('OP_DUP OP_HASH160 ... OP_EQUALVERIFY OP_CHECKSIG').toHex()
}]
})
} catch (error) {
if (error.code === 'INSUFFICIENT_FUNDS') {
console.log('Not enough funds available')
// Handle insufficient funds
} else if (error.code === 'WALLET_NOT_CONNECTED') {
console.log('Wallet connection required')
await wallet.connectToSubstrate()
} else {
console.error('Unexpected error:', error)
}
}
async function retryOperation<T>(
operation: () => Promise<T>,
maxRetries: number = 3,
baseDelay: number = 1000
): Promise<T> {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
return await operation()
} catch (error) {
if (attempt === maxRetries) throw error
// Only retry on network errors
if (!['NETWORK_ERROR', 'TIMEOUT_ERROR', 'NODE_UNAVAILABLE'].includes(error.code)) {
throw error
}
const delay = baseDelay * Math.pow(2, attempt)
await new Promise(resolve => setTimeout(resolve, delay))
}
}
throw new Error('Max retries exceeded')
}
function categorizeError(error: WalletErrorObject): 'user' | 'network' | 'system' | 'config' {
const userErrors = ['ACTION_REJECTED', 'AUTHENTICATION_FAILED', 'WALLET_LOCKED']
const networkErrors = ['NETWORK_ERROR', 'NODE_UNAVAILABLE', 'BROADCAST_FAILED', 'TIMEOUT_ERROR']
const systemErrors = ['INVALID_TRANSACTION', 'SIGNATURE_VERIFICATION_FAILED', 'ENCRYPTION_FAILED']
const configErrors = ['INVALID_CONFIG', 'UNSUPPORTED_NETWORK']
if (userErrors.includes(error.code)) return 'user'
if (networkErrors.includes(error.code)) return 'network'
if (systemErrors.includes(error.code)) return 'system'
if (configErrors.includes(error.code)) return 'config'
return 'system' // Default category
}
Symptoms: Error during createAction
calls
Cause: Wallet input selection issues
Solutions:
Symptoms: Error despite wallet showing balance
Cause: UTXOs not properly selected by wallet
Solutions:
listOutputs()
Symptoms: Valid transactions rejected by network
Cause: Various network or validation issues
Solutions:
Symptoms: Cannot connect to wallet substrate
Cause: Wallet not running or permission issues
Solutions:
function validateTransaction(tx: Transaction): string[] {
const errors: string[] = []
if (tx.inputs.length === 0) {
errors.push('Transaction must have at least one input')
}
if (tx.outputs.length === 0) {
errors.push('Transaction must have at least one output')
}
const totalInput = tx.inputs.reduce((sum, input) => sum + input.satoshis, 0)
const totalOutput = tx.outputs.reduce((sum, output) => sum + output.satoshis, 0)
if (totalInput <= totalOutput) {
errors.push('Insufficient input value to cover outputs and fees')
}
return errors
}
async function testNetworkConnectivity(chainTracker: ChainTracker): Promise<boolean> {
try {
const height = await chainTracker.getHeight()
return height > 0
} catch (error) {
console.error('Network connectivity test failed:', error)
return false
}
}
async function checkWalletHealth(wallet: WalletClient): Promise<{
connected: boolean
authenticated: boolean
balance: number
errors: string[]
}> {
const result = {
connected: false,
authenticated: false,
balance: 0,
errors: [] as string[]
}
try {
await wallet.connectToSubstrate()
result.connected = true
} catch (error) {
result.errors.push(`Connection failed: ${error.message}`)
}
try {
const outputs = await wallet.listOutputs({ limit: 1 })
result.authenticated = true
result.balance = outputs.totalValue || 0
} catch (error) {
result.errors.push(`Authentication failed: ${error.message}`)
}
return result
}
class ErrorRecoveryManager {
private retryAttempts = new Map<string, number>()
private maxRetries = 3
async executeWithRecovery<T>(
operation: () => Promise<T>,
operationId: string
): Promise<T> {
try {
const result = await operation()
this.retryAttempts.delete(operationId)
return result
} catch (error) {
return this.handleError(error, operation, operationId)
}
}
private async handleError<T>(
error: WalletErrorObject,
operation: () => Promise<T>,
operationId: string
): Promise<T> {
const attempts = this.retryAttempts.get(operationId) || 0
if (attempts >= this.maxRetries) {
this.retryAttempts.delete(operationId)
throw error
}
// Implement recovery strategies based on error type
switch (error.code) {
case 'WALLET_NOT_CONNECTED':
await this.reconnectWallet()
break
case 'NETWORK_ERROR':
await this.switchToBackupNode()
break
case 'INSUFFICIENT_FUNDS':
await this.waitForConfirmations()
break
default:
throw error // No recovery strategy available
}
this.retryAttempts.set(operationId, attempts + 1)
return this.executeWithRecovery(operation, operationId)
}
private async reconnectWallet(): Promise<void> {
// Implement wallet reconnection logic
}
private async switchToBackupNode(): Promise<void> {
// Implement node failover logic
}
private async waitForConfirmations(): Promise<void> {
// Wait for pending transactions to confirm
await new Promise(resolve => setTimeout(resolve, 30000))
}
}
class ErrorLogger {
static log(error: WalletErrorObject, context?: Record<string, any>): void {
const logEntry = {
timestamp: new Date().toISOString(),
code: error.code,
message: error.description,
context: { ...error.context, ...context },
stack: error.stack
}
// Log to appropriate destination based on severity
if (this.isCriticalError(error.code)) {
console.error('CRITICAL ERROR:', logEntry)
} else {
console.warn('ERROR:', logEntry)
}
}
private static isCriticalError(code: string): boolean {
return [
'INVALID_PRIVATE_KEY',
'SIGNATURE_VERIFICATION_FAILED',
'CHAIN_VALIDATION_FAILED'
].includes(code)
}
}
function getUserFriendlyMessage(error: WalletErrorObject): string {
const messages: Record<string, string> = {
'INSUFFICIENT_FUNDS': 'You don\'t have enough funds for this transaction.',
'ACTION_REJECTED': 'Transaction was cancelled.',
'WALLET_NOT_CONNECTED': 'Please connect your wallet to continue.',
'NETWORK_ERROR': 'Network connection issue. Please try again.',
'INVALID_TRANSACTION': 'Transaction format is invalid. Please check your inputs.'
}
return messages[error.code] || 'An unexpected error occurred. Please try again.'
}
This comprehensive error reference provides developers with the tools and knowledge needed to handle all types of errors that may occur when using the BSV TypeScript SDK.