Skip to main content

Overview

TrezorConnect uses a consistent error handling pattern across all methods. Every method returns a result object with a success field that indicates whether the operation completed successfully.

Error Response Structure

All errors follow a standardized format:
{
  success: false,
  error: {
    code: string,    // Error code identifier
    message: string  // Human-readable error message
  },
  device?: Device    // Device info (when applicable)
}

Basic Error Handling

const result = await TrezorConnect.getAddress({
  path: "m/49'/0'/0'/0/0",
  coin: 'btc'
});

if (result.success) {
  console.log('Address:', result.payload.address);
} else {
  console.error('Error:', result.error.message);
  console.error('Code:', result.error.code);
}

Error Categories

Errors are organized into several categories:
Errors that occur during TrezorConnect initialization:
Error CodeMessageCause
Init_NotInitializedTrezorConnect not initializedCalled method before init()
Init_AlreadyInitializedTrezorConnect has been already initializedCalled init() multiple times
Init_ManifestMissingManifest not setMissing manifest in init()
Init_IframeBlockedIframe blockedAd-blocker blocking iframe
Init_IframeTimeoutIframe timeoutIframe failed to load
// Prevent initialization errors
try {
  await TrezorConnect.init({
    manifest: {
      email: '[email protected]',
      appUrl: 'https://example.com'
    }
  });
} catch (error) {
  if (error.code === 'Init_IframeBlocked') {
    showMessage('Please disable ad-blocker for this site');
  }
}
Errors related to device state and connectivity:
Error CodeMessageCause
Device_NotFoundDevice not foundNo device connected
Device_DisconnectedDevice disconnectedDevice unplugged during operation
Device_UsedElsewhereDevice is used in another windowAnother app is using the device
Device_InvalidStatePassphrase is incorrectWrong passphrase entered
Device_CallInProgressDevice call in progressAttempted concurrent calls
Device_MultipleNotSupportedMultiple devices are not supportedMultiple devices connected
const result = await TrezorConnect.getAddress({ /* ... */ });

if (!result.success) {
  switch (result.error.code) {
    case 'Device_NotFound':
      showMessage('Please connect your Trezor device');
      break;
    case 'Device_Disconnected':
      showMessage('Device was disconnected. Please reconnect.');
      break;
    case 'Device_UsedElsewhere':
      showMessage('Device is being used by another application');
      break;
    case 'Device_InvalidState':
      showMessage('Incorrect passphrase entered');
      break;
  }
}
Errors during method execution:
Error CodeMessageCause
Method_InvalidParameterInvalid parameterInvalid method parameters
Method_NotAllowedMethod not allowedMethod unavailable in current mode
Method_PermissionsNotGrantedPermissions not grantedUser denied permission
Method_CancelCanceledUser canceled operation
Method_InterruptedPopup closedPopup/window closed
Method_UnknownCoinCoin not foundInvalid coin identifier
Method_AddressNotMatchAddresses do not matchAddress validation failed
const result = await TrezorConnect.getAddress({
  path: "m/49'/0'/0'/0/0",
  coin: 'btc',
  address: 'expected-address'
});

if (!result.success) {
  if (result.error.code === 'Method_AddressNotMatch') {
    showError('Address mismatch - possible security issue!');
  }
}
Communication layer errors:
Error CodeMessageCause
Transport_MissingTransport is missingNo transport available
Popup_ConnectionMissingUnable to establish connectionCommunication failure
import { TRANSPORT_EVENT, TRANSPORT } from '@trezor/connect';

TrezorConnect.on(TRANSPORT_EVENT, (event) => {
  if (event.type === TRANSPORT.ERROR) {
    console.error('Transport error:', event.payload.error);
    
    if (event.payload.code === 'Transport_Missing') {
      showMessage('Please install Trezor Bridge');
    }
  }
});
Blockchain backend errors:
Error CodeMessageCause
Backend_NotSupportedBlockchainLink settings not foundNo backend for this coin
Backend_DisconnectedBackend disconnectedLost connection to backend
Backend_InvalidInvalid backendWrong backend configuration
Backend_Error(varies)Backend-specific error
const result = await TrezorConnect.getAccountInfo({
  path: "m/84'/0'/0'",
  coin: 'btc'
});

if (!result.success) {
  if (result.error.code === 'Backend_Disconnected') {
    showMessage('Lost connection to blockchain. Reconnecting...');
    // Will automatically reconnect
  }
}
Firmware-related errors:
Error CodeMessageCause
Device_FwException(varies)Firmware version issue
Firmware_OldDevice firmware is too oldOutdated firmware
Firmware_OutdatedFirmware update recommendedNon-critical update available
Firmware_NotSupportedFirmware not supportedUnsupported version
import { UI_EVENT, UI_REQUEST } from '@trezor/connect';

TrezorConnect.on(UI_EVENT, async (event) => {
  if (event.type === UI_REQUEST.FIRMWARE_OLD) {
    const shouldUpdate = await confirm(
      'Your firmware is outdated. Update now?'
    );
    
    if (shouldUpdate) {
      await TrezorConnect.firmwareUpdate();
    }
  }
});

Common Error Patterns

User Cancellation

const result = await TrezorConnect.signTransaction({ /* ... */ });

if (!result.success) {
  if (result.error.code === 'Method_Cancel') {
    // User clicked cancel
    showMessage('Transaction canceled');
    return;
  }
  
  if (result.error.code === 'Method_Interrupted') {
    // User closed popup
    showMessage('Operation interrupted');
    return;
  }
}

Passphrase Validation

Always validate device state to detect passphrase mismatches.
let expectedState: string | undefined;

// First operation - store state
const firstResult = await TrezorConnect.getAddress({
  path: "m/49'/0'/0'/0/0",
  coin: 'btc'
});

if (firstResult.success && firstResult.device) {
  expectedState = firstResult.device.state;
}

// Later operation - validate state
const secondResult = await TrezorConnect.signTransaction({ /* ... */ });

if (!secondResult.success) {
  if (secondResult.error.code === 'Device_InvalidState') {
    showError('Wrong passphrase entered!');
    return;
  }
}

// Additional validation
if (secondResult.success && secondResult.device) {
  if (secondResult.device.state !== expectedState) {
    throw new Error('Device state mismatch - different passphrase used');
  }
}

Connection Issues

import { DEVICE_EVENT, DEVICE } from '@trezor/connect';

class ConnectionHandler {
  private isDeviceConnected = false;
  private reconnectAttempts = 0;
  private maxReconnectAttempts = 3;

  constructor() {
    TrezorConnect.on(DEVICE_EVENT, this.handleDeviceEvent);
  }

  handleDeviceEvent = (event) => {
    if (event.type === DEVICE.CONNECT) {
      this.isDeviceConnected = true;
      this.reconnectAttempts = 0;
      console.log('Device connected');
    }
    
    if (event.type === DEVICE.DISCONNECT) {
      this.isDeviceConnected = false;
      this.handleDisconnection();
    }
  };

  async handleDisconnection() {
    if (this.reconnectAttempts < this.maxReconnectAttempts) {
      this.reconnectAttempts++;
      showMessage(`Device disconnected. Waiting for reconnection... (${this.reconnectAttempts}/${this.maxReconnectAttempts})`);
      
      // Wait for device to reconnect
      await this.waitForReconnection(5000);
    } else {
      showError('Device disconnected. Please reconnect manually.');
    }
  }

  waitForReconnection(timeout: number): Promise<boolean> {
    return new Promise((resolve) => {
      const timer = setTimeout(() => {
        resolve(false);
      }, timeout);

      const checkConnection = () => {
        if (this.isDeviceConnected) {
          clearTimeout(timer);
          resolve(true);
        }
      };

      const interval = setInterval(checkConnection, 100);
      setTimeout(() => clearInterval(interval), timeout);
    });
  }
}

Invalid Parameters

function validatePath(path: string): boolean {
  // BIP32 path validation
  const pathRegex = /^m(\/\d+'?)+$/;
  return pathRegex.test(path);
}

try {
  const path = "m/49'/0'/0'/0/0";
  
  if (!validatePath(path)) {
    throw new Error('Invalid derivation path');
  }
  
  const result = await TrezorConnect.getAddress({
    path,
    coin: 'btc'
  });
  
  if (!result.success) {
    if (result.error.code === 'Method_InvalidParameter') {
      console.error('Parameter validation failed:', result.error.message);
    }
  }
} catch (error) {
  handleValidationError(error);
}

Error Recovery Strategies

Retry Logic

async function callWithRetry<T>(
  operation: () => Promise<T>,
  maxRetries = 3,
  delay = 1000
): Promise<T> {
  let lastError: Error;
  
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      const result = await operation();
      
      if (!result.success) {
        // Check if error is retryable
        if (isRetryableError(result.error.code)) {
          lastError = new Error(result.error.message);
          await sleep(delay * (attempt + 1));
          continue;
        }
        // Non-retryable error
        throw new Error(result.error.message);
      }
      
      return result;
    } catch (error) {
      lastError = error;
      if (attempt < maxRetries - 1) {
        await sleep(delay * (attempt + 1));
      }
    }
  }
  
  throw lastError!;
}

function isRetryableError(code: string): boolean {
  const retryableCodes = [
    'Backend_Disconnected',
    'Transport_Missing',
    'Device_CallInProgress'
  ];
  return retryableCodes.includes(code);
}

// Usage
const result = await callWithRetry(() =>
  TrezorConnect.getAddress({
    path: "m/49'/0'/0'/0/0",
    coin: 'btc'
  })
);

Graceful Degradation

class TrezorService {
  async getAddress(path: string, coin: string) {
    try {
      const result = await TrezorConnect.getAddress({ path, coin });
      
      if (result.success) {
        return { address: result.payload.address };
      }
      
      // Handle specific errors
      switch (result.error.code) {
        case 'Device_NotFound':
          return { error: 'DEVICE_NOT_FOUND', fallback: 'watch-only' };
          
        case 'Method_PermissionsNotGranted':
          return { error: 'PERMISSION_DENIED', fallback: null };
          
        case 'Backend_Disconnected':
          return { error: 'NETWORK_ERROR', fallback: 'cached' };
          
        default:
          return { error: 'UNKNOWN', message: result.error.message };
      }
    } catch (error) {
      console.error('Unexpected error:', error);
      return { error: 'EXCEPTION', message: error.message };
    }
  }
}

Error Logging

Implement comprehensive error logging for debugging and monitoring.
interface ErrorLog {
  timestamp: number;
  method: string;
  errorCode: string;
  errorMessage: string;
  deviceInfo?: any;
  context?: any;
}

class ErrorLogger {
  private logs: ErrorLog[] = [];
  
  log(method: string, error: any, context?: any) {
    const log: ErrorLog = {
      timestamp: Date.now(),
      method,
      errorCode: error.code || 'UNKNOWN',
      errorMessage: error.message,
      context
    };
    
    this.logs.push(log);
    
    // Send to monitoring service
    this.sendToMonitoring(log);
    
    // Log to console in development
    if (process.env.NODE_ENV === 'development') {
      console.error('TrezorConnect Error:', log);
    }
  }
  
  async sendToMonitoring(log: ErrorLog) {
    // Send to Sentry, LogRocket, etc.
    try {
      await fetch('/api/errors', {
        method: 'POST',
        body: JSON.stringify(log)
      });
    } catch (e) {
      console.error('Failed to send error log:', e);
    }
  }
  
  getRecentErrors(limit = 10): ErrorLog[] {
    return this.logs.slice(-limit);
  }
}

const errorLogger = new ErrorLogger();

// Usage
const result = await TrezorConnect.getAddress({ /* ... */ });

if (!result.success) {
  errorLogger.log('getAddress', result.error, {
    path: "m/49'/0'/0'/0/0",
    coin: 'btc'
  });
}

User-Friendly Error Messages

function getUserFriendlyMessage(errorCode: string): string {
  const messages: Record<string, string> = {
    'Device_NotFound': 'Please connect your Trezor device and try again.',
    'Device_Disconnected': 'Your Trezor was disconnected. Please reconnect it.',
    'Device_UsedElsewhere': 'Your Trezor is being used by another application. Please close other apps and try again.',
    'Device_InvalidState': 'The passphrase you entered doesn\'t match. Please try again.',
    'Method_Cancel': 'You canceled the operation.',
    'Method_PermissionsNotGranted': 'Permission denied. Please approve the request on your device.',
    'Transport_Missing': 'Trezor Bridge is not installed or running. Please install it from trezor.io/start',
    'Backend_Disconnected': 'Lost connection to blockchain. Please check your internet connection.',
    'Firmware_Old': 'Your Trezor firmware is outdated. Please update it for security.',
  };
  
  return messages[errorCode] || 'An unexpected error occurred. Please try again.';
}

// Usage
const result = await TrezorConnect.signTransaction({ /* ... */ });

if (!result.success) {
  const friendlyMessage = getUserFriendlyMessage(result.error.code);
  showNotification(friendlyMessage, 'error');
}

TypeScript Error Types

import type { TrezorError } from '@trezor/connect';

// Type-safe error handling
function handleTrezorError(error: TrezorError) {
  switch (error.code) {
    case 'Device_NotFound':
      // Handle device not found
      break;
    case 'Method_Cancel':
      // Handle cancellation
      break;
    // TypeScript ensures all error codes are handled
  }
}

// Custom error types
class TrezorOperationError extends Error {
  constructor(
    public code: string,
    message: string,
    public originalError?: any
  ) {
    super(message);
    this.name = 'TrezorOperationError';
  }
}

// Wrap errors
async function safeGetAddress(path: string, coin: string) {
  const result = await TrezorConnect.getAddress({ path, coin });
  
  if (!result.success) {
    throw new TrezorOperationError(
      result.error.code,
      result.error.message,
      result.error
    );
  }
  
  return result.payload.address;
}

Best Practices

  1. Always check success field before accessing payload
  2. Handle specific error codes for better UX
  3. Implement retry logic for transient errors
  4. Log errors for debugging and monitoring
  5. Provide user-friendly messages instead of raw error codes
  6. Validate inputs before calling methods
  7. Handle device disconnections gracefully
  8. Test error scenarios in your application
Never expose sensitive error details (device paths, states) in production logs or to users.

Next Steps

Methods

Learn about TrezorConnect methods

Events

Understand event handling

Device Management

Manage devices effectively

Build docs developers (and LLMs) love