> ## Documentation Index
> Fetch the complete documentation index at: https://docs.amberdata.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Advanced Configuration & Error Handling

> Master error handling, troubleshooting, and advanced configuration options for production WebSocket implementations.

This guide covers advanced error handling, troubleshooting scenarios, and production-ready configuration for Amberdata's WebSocket services.

## Error Handling & Response Codes

This section describes common WebSocket subscription errors and how to resolve them.

### Common Error Scenarios

#### 1. Wildcards Not Supported for This Feature

<Warning> Wildcard subscriptions are **not supported** for **Tickers** or **Order Book Event** streams.</Warning>

**Error Response:**

```json theme={null}
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "description": "not authorized to access this resource",
    "code": 403
  }
}
```

**Cause**: Attempting to subscribe to Tickers or Order Book Events without explicitly specifying both:

* exchange
* pair/instrument

**Solution**:

```javascript theme={null}
// ❌ This will fail
{
  "params": ["market:spot:tickers", {"exchange": "binance"}]
}

// ✅ Use explicit instrument subscriptions
{
  "params": ["market:spot:tickers", {"exchange": "binance", "pair": "btc_usdt"}]
}
```

#### 2. Invalid Subscription Error

**Error Response:**

```json theme={null}
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "description": "subscription 'market:spot:tickers:snapsh000ts' is not supported",
    "code": 400
  }
}
```

**Cause**: Attempting to subscribe with non-existent or misspelled subscription name.

**Solution**:

```javascript theme={null}
// ❌ This will fail
{
  "params": ["market:spot:tickers:snapsh000ts", {"exchange": "bitget", "pair": "btc_usdt"}]
}

// ✅ Use a valid subscription name
{
  "params": ["market:spot:tickers:snapshots", {"exchange": "bitget", "pair": "btc_usdt"}]
}
```

#### 3. Invalid API Key

**Error**: Connection closes with message `invalid api key '<api_key>'`

**Solution**: Verify API key and permissions:

```javascript theme={null}
const connectWithRetry = (apiKey, maxRetries = 3) => {
  let retries = 0;

  const connect = () => {
    const ws = new WebSocket('wss://ws.amberdata.com', {
      headers: {
        'x-api-key': apiKey,
        'x-amberdata-blockchain-id': 'ethereum-mainnet'
      }
    });

    ws.on('error', (error) => {
      if (error.message.includes('invalid api key') && retries < maxRetries) {
        retries++;
        console.log(`Retrying connection (${retries}/${maxRetries})...`);
        setTimeout(connect, 1000 * retries); // Exponential backoff
      } else {
        console.error('Connection failed:', error);
      }
    });

    return ws;
  };

  return connect();
};
```

#### 4. Missing API Key

**Error Response:**

```json theme={null}
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "description": "missing api key",
    "code": 401
  }
}
```

**Cause**: Attempting to connect/subscribe with a missing API key.

**Solution**:

```javascript theme={null}
// ❌ This will fail
const ws = new WebSocket('wss://ws.amberdata.com/spot');

// ✅ Must provide API key
const ws = new WebSocket('wss://ws.amberdata.com/spot', {
  headers: { 'x-api-key': 'VALID_API_KEY_HERE' }
});
```

#### 5. Missing Parameter(s)

**Error Response:**

```json theme={null}
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "description": "params must contain either 1 or 2 elements",
    "code": 400
  }
}
```

**Cause**: Attempting to subscribe with no parameters.

**Solution**:

```javascript theme={null}
// ❌ This will fail
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "subscribe"
}

// ✅ Must provide params
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "subscribe",
  "params": [
    "market:spot:trades",
    {
      "pair": "btc_usd",
      "exchange": "gdax"
    }
  ]
}
```

## Production Error Handling Patterns

### Robust Reconnection Logic

```javascript theme={null}
class RobustWebSocket {
  constructor(url, options = {}) {
    this.url = url;
    this.options = options;
    this.reconnectAttempts = 0;
    this.maxReconnectAttempts = options.maxReconnectAttempts || 10;
    this.reconnectDelay = options.reconnectDelay || 1000;
    this.subscriptions = new Map();

    this.connect();
  }

  connect() {
    try {
      this.ws = new WebSocket(this.url, {
        headers: this.options.headers
      });

      this.ws.on('open', () => {
        console.log('WebSocket connected');
        this.reconnectAttempts = 0;
        this.resubscribeAll();
      });

      this.ws.on('message', (data) => {
        this.handleMessage(JSON.parse(data));
      });

      this.ws.on('close', () => {
        console.log('WebSocket disconnected');
        this.handleReconnect();
      });

      this.ws.on('error', (error) => {
        console.error('WebSocket error:', error);
        this.handleReconnect();
      });

    } catch (error) {
      console.error('Connection failed:', error);
      this.handleReconnect();
    }
  }

  handleReconnect() {
    if (this.reconnectAttempts < this.maxReconnectAttempts) {
      this.reconnectAttempts++;
      const delay = this.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1);

      console.log(`Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})`);
      setTimeout(() => this.connect(), delay);
    } else {
      console.error('Max reconnection attempts reached');
    }
  }

  subscribe(params) {
    const id = Date.now();
    const request = {
      jsonrpc: "2.0",
      id: id,
      method: "subscribe",
      params: params
    };

    // Store subscription for reconnection
    this.subscriptions.set(id, params);

    if (this.ws && this.ws.readyState === WebSocket.OPEN) {
      this.ws.send(JSON.stringify(request));
    }
  }

  resubscribeAll() {
    for (const [id, params] of this.subscriptions) {
      this.subscribe(params);
    }
  }

  handleMessage(message) {
    if (message.error) {
      console.error('Subscription error:', message.error);
      this.handleSubscriptionError(message);
    } else if (message.method === 'subscription') {
      this.handleSubscriptionData(message.params);
    }
  }

  handleSubscriptionError(message) {
    const { error, id } = message;

    switch (error.code) {
      case 400:
        if (error.description.includes('Wildcard subscription')) {
          console.error('Wildcard subscription not allowed for:', id);
          // Remove invalid subscription
          this.subscriptions.delete(id);
        } else if (error.description.includes('Max subscription limit')) {
          console.error('Subscription limit reached');
          // Implement connection pooling logic
          this.handleSubscriptionLimit();
        }
        break;
      default:
        console.error('Unknown subscription error:', error);
    }
  }
}
```

### Message Processing & Buffering

```javascript theme={null}
class MessageProcessor {
  constructor(batchSize = 100, flushInterval = 1000) {
    this.buffer = [];
    this.batchSize = batchSize;
    this.flushInterval = flushInterval;
    this.processing = false;

    // Flush buffer periodically
    setInterval(() => this.flush(), flushInterval);
  }

  addMessage(message) {
    this.buffer.push({
      ...message,
      timestamp: Date.now()
    });

    if (this.buffer.length >= this.batchSize) {
      this.flush();
    }
  }

  async flush() {
    if (this.processing || this.buffer.length === 0) return;

    this.processing = true;
    const batch = this.buffer.splice(0, this.batchSize);

    try {
      await this.processBatch(batch);
    } catch (error) {
      console.error('Batch processing failed:', error);
      // Re-queue failed messages
      this.buffer.unshift(...batch);
    } finally {
      this.processing = false;
    }
  }

  async processBatch(messages) {
    // Process messages in batch
    const grouped = this.groupMessagesByType(messages);

    for (const [type, msgs] of Object.entries(grouped)) {
      await this.processMessageType(type, msgs);
    }
  }

  groupMessagesByType(messages) {
    return messages.reduce((groups, msg) => {
      const type = this.getMessageType(msg);
      if (!groups[type]) groups[type] = [];
      groups[type].push(msg);
      return groups;
    }, {});
  }
}
```

## Advanced Configuration

### Connection Optimization

**Multiple Endpoint Strategy:**

```javascript theme={null}
class MultiEndpointManager {
  constructor() {
    this.connections = {
      spot: new RobustWebSocket('wss://ws.amberdata.com/spot', {
        headers: { 'x-api-key': process.env.API_KEY }
      }),
      futures: new RobustWebSocket('wss://ws.amberdata.com/futures', {
        headers: { 'x-api-key': process.env.API_KEY }
      }),
      options: new RobustWebSocket('wss://ws.amberdata.com/options', {
        headers: { 'x-api-key': process.env.API_KEY }
      }),
      blockchain: new RobustWebSocket('wss://ws.amberdata.com', {
        headers: {
          'x-api-key': process.env.API_KEY,
          'x-amberdata-blockchain-id': 'ethereum-mainnet'
        }
      })
    };
  }

  subscribe(dataType, params) {
    const endpoint = this.getEndpointForDataType(dataType);
    if (endpoint) {
      this.connections[endpoint].subscribe([dataType, params]);
    } else {
      throw new Error(`No endpoint configured for data type: ${dataType}`);
    }
  }

  getEndpointForDataType(dataType) {
    if (dataType.startsWith('market:spot:')) return 'spot';
    if (dataType.startsWith('market:futures:')) return 'futures';
    if (dataType.startsWith('market:options:')) return 'options';
    if (dataType.includes('block') || dataType.includes('transaction')) return 'blockchain';
    return null;
  }
}
```

### Health Monitoring

```javascript theme={null}
class ConnectionHealthMonitor {
  constructor(connections) {
    this.connections = connections;
    this.metrics = {
      messageCount: 0,
      errorCount: 0,
      lastMessageTime: Date.now(),
      connectionStatus: {}
    };

    this.startHealthChecks();
  }

  startHealthChecks() {
    // Check connection health every 30 seconds
    setInterval(() => this.performHealthCheck(), 30000);

    // Send ping every 10 seconds
    setInterval(() => this.sendPings(), 10000);
  }

  performHealthCheck() {
    const now = Date.now();
    const timeSinceLastMessage = now - this.metrics.lastMessageTime;

    // Alert if no messages in 60 seconds
    if (timeSinceLastMessage > 60000) {
      console.warn('No messages received in 60 seconds');
      this.triggerReconnection();
    }

    // Log health metrics
    console.log('Health Status:', {
      messageCount: this.metrics.messageCount,
      errorCount: this.metrics.errorCount,
      timeSinceLastMessage: timeSinceLastMessage,
      activeConnections: Object.keys(this.connections).length
    });
  }

  sendPings() {
    for (const [name, connection] of Object.entries(this.connections)) {
      if (connection.ws && connection.ws.readyState === WebSocket.OPEN) {
        connection.ws.ping();
      }
    }
  }

  recordMessage() {
    this.metrics.messageCount++;
    this.metrics.lastMessageTime = Date.now();
  }

  recordError() {
    this.metrics.errorCount++;
  }
}
```

## Enterprise Features & Customization

### Custom Rate Limits

Enterprise customers can request custom configurations:

```javascript theme={null}
// Example enterprise configuration request
const enterpriseConfig = {
  maxConnections: 100,
  maxSubscriptionsPerConnection: 500,
  wildcardSupport: true,
  customEndpoints: true,
  prioritySupport: true,
  dedicatedInfrastructure: true
};

// Contact sales team with requirements
```

### Advanced Subscription Patterns

**Conditional Subscriptions:**

```javascript theme={null}
class ConditionalSubscriber {
  constructor(websocket) {
    this.ws = websocket;
    this.conditions = new Map();
  }

  subscribeWithCondition(params, condition) {
    const subscriptionId = this.ws.subscribe(params);
    this.conditions.set(subscriptionId, condition);
  }

  handleMessage(message) {
    const { subscription, result } = message.params;
    const condition = this.conditions.get(subscription);

    if (condition && condition(result)) {
      this.processMessage(result);
    }
  }
}
```

## Troubleshooting Checklist

### Connection Issues

* [ ] Verify API key is valid and active
* [ ] Check network connectivity and firewall settings
* [ ] Ensure proper WebSocket library configuration
* [ ] Verify endpoint URL is correct for data type

### Subscription Issues

* [ ] Confirm subscription parameters are valid
* [ ] Check subscription limits haven't been exceeded
* [ ] Verify exchange and pair names are correct
* [ ] Ensure proper JSON-RPC 2.0 format

### Performance Issues

* [ ] Monitor message processing latency
* [ ] Check for memory leaks in message handling
* [ ] Verify connection distribution across endpoints
* [ ] Review subscription patterns for efficiency

### Data Quality Issues

* [ ] Implement message deduplication
* [ ] Add timestamp validation
* [ ] Monitor for missing sequence numbers
* [ ] Verify data format expectations

## Getting Support

For enterprise-level support and custom configurations:

* **Technical Issues**: Contact support with connection logs and error messages
* **Custom Rate Limits**: Reach out to sales team with requirements
* **Performance Optimization**: Schedule consultation for high-volume use cases
* **Integration Support**: Request dedicated technical account management

Enterprise customers receive priority support with guaranteed response times and dedicated infrastructure options.
