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

# Errors

> WebSocket error handling and error codes

## Error Codes

The WebSocket may close the connection with specific error codes. In addition to standard WebSocket codes, VoxFi uses custom codes in the 4000-4999 range.

### VoxFi Custom Codes

#### 4001 - Unauthorized

**Cause**: Invalid or missing API key when trying to subscribe to the `user` channel.

**When it occurs**: When trying to subscribe to the `user` channel without providing `auth` or with an invalid API key.

**Solution**:

* Verify that you are providing the `auth` field in the subscribe message;
* Confirm that the API key is correct and active;
* Check if the API key has expired or been disabled;
* Verify that your IP is on the API key's whitelist.

#### 4002 - Invalid Params

**Cause**: Invalid connection parameters.

**When it occurs**: During initial connection validation, when session data is invalid or missing.

**Common error messages:**

* `"session is required"`: Invalid or missing session

**Solution**: Verify that you are using the correct WebSocket URL and that the connection is being established correctly.

#### 4003 - Server Error

**Cause**: Internal server error.

**When it occurs**: When an unexpected error occurs on the server while processing your request.

**Solution**: Try again after a few seconds. If the problem persists, contact support.

#### 4004 - Invalid Message

**Cause**: Invalid message or incorrect parameters in the subscribe/unsubscribe message.

**When it occurs**: When sending messages with invalid format or content.

**Possible causes:**

* Invalid `channel` field (must be `"user"`, `"market"` or `"event"`);
* Invalid `filter` field (must be `"all"`, `"orderbook"`, `"trades"` or empty);
* Missing required fields (`markets` for market channel, `events` for event channel, `auth` for user channel);
* Invalid JSON format;
* Invalid message type (must be `"subscribe"` or `"unsubscribe"`).

**Common error messages:**

* `"invalid channel"`: Specified channel does not exist;
* `"invalid filter"`: Specified filter is invalid;
* `"invalid message type"`: Invalid message type.

**Solution**: Check the message structure and ensure all required fields are present and in the correct format.

### Standard WebSocket Codes

In addition to custom codes, the WebSocket may return standard codes:

* **1000**: Normal closure (not an error);
* **1001**: Endpoint going away;
* **1002**: Protocol error;
* **1006**: Connection closed abnormally (without close code);
* **1011**: Internal server error.

## Error Handling

<CodeGroup>
  ```javascript JavaScript theme={null}
  const ws = new WebSocket('wss://data-ws-dev.voxfi.com.br');

  ws.onerror = (error) => {
    console.error('WebSocket error:', error);
  };

  ws.onclose = (event) => {
    console.log('Connection closed:', event.code, event.reason);
    
    // Handle different error codes
    switch (event.code) {
      case 4001:
        console.error('Unauthorized. Check your API key.');
        break;
      case 4002:
        console.error('Invalid parameters. Check the connection.');
        break;
      case 4003:
        console.error('Server error. Try again later.');
        break;
      case 4004:
        console.error('Invalid message. Check the message format.');
        break;
      case 1002:
        console.error('Protocol error. Check the URL and message format.');
        break;
      case 1006:
        console.error('Connection closed abnormally. Possible network issue.');
        break;
      default:
        console.error('Unknown error:', event.code, event.reason);
    }
    
    // Implement reconnection if necessary
    if (event.code !== 1000) { // 1000 = normal closure
      setTimeout(() => {
        console.log('Attempting to reconnect...');
        connect(); // Your connection function
      }, 5000);
    }
  };
  ```

  ```python Python theme={null}
  import asyncio
  import websockets
  import json

  async def connect_with_error_handling():
      uri = "wss://data-ws-dev.voxfi.com.br"
      
      try:
          async with websockets.connect(uri) as websocket:
              # Your logic here
              await websocket.send(json.dumps({
                  "type": "subscribe",
                  "channel": "market",
                  "markets": ["market-id-1"]
              }))
              
              async for message in websocket:
                  data = json.loads(message)
                  print("Message received:", data)
                  
      except websockets.exceptions.InvalidStatusCode as e:
          print(f"Connection error: {e.status_code}")
          if e.status_code == 403:
              print("Unauthorized. Check your API key.")
      except websockets.exceptions.ConnectionClosed as e:
          print(f"Connection closed: code {e.code}, reason: {e.reason}")
          
          if e.code == 4001:
              print("Unauthorized. Check your API key.")
          elif e.code == 4002:
              print("Invalid parameters. Check the connection.")
          elif e.code == 4003:
              print("Server error. Try again later.")
          elif e.code == 4004:
              print("Invalid message. Check the message format.")
          elif e.code == 1002:
              print("Protocol error. Check the URL and message format.")
          elif e.code == 1006:
              print("Connection closed abnormally. Possible network issue.")
      except Exception as e:
          print(f"Unexpected error: {e}")

  asyncio.run(connect_with_error_handling())
  ```
</CodeGroup>

## Error Messages

In addition to close codes, the WebSocket returns error messages in the `reason` field when closing the connection. These messages provide specific details about the error:

### Common Error Messages

* **`"session is required"`** (code 4002): Invalid or missing session during initial validation;
* **`"invalid channel"`** (code 4004): Specified channel does not exist (must be `"user"`, `"market"` or `"event"`);
* **`"invalid filter"`** (code 4004): Specified filter is invalid (must be `"all"`, `"orderbook"`, `"trades"` or empty);
* **`"invalid message type"`** (code 4004): Invalid message type (must be `"subscribe"` or `"unsubscribe"`);
* **`"failed to check x-api-key"`** (code 4001): Failed to validate API key;
* Go JSON error messages when there is a failure to unmarshal the message (code 4004).

## Error Handling Best Practices

1. **Always Handle onclose**: Implement handling for the `onclose` event to detect disconnections;
2. **Check Error Codes**: Use error codes to determine the cause and take appropriate actions;
3. **Smart Reconnection**: Implement automatic reconnection with exponential backoff for temporary errors;
4. **Don't Reconnect for Permanent Errors**: Errors like 1003 (unauthorized) or 1008 (invalid message) indicate problems that need to be fixed before reconnecting;
5. **Logging**: Log all errors for debugging and monitoring;
6. **Pre-validation**: Validate messages before sending to avoid 1008 errors;
7. **Timeout Handling**: Implement timeout for connections that don't respond.

## Exponential Backoff Reconnection Example

```javascript theme={null}
let reconnectDelay = 1000; // Start with 1 second
const maxDelay = 60000; // Maximum of 60 seconds

function connect() {
  const ws = new WebSocket('wss://data-ws-dev.voxfi.com.br');
  
  ws.onopen = () => {
    console.log('Connected');
    reconnectDelay = 1000; // Reset delay on success
    // Resubscribe to all channels
    resubscribe(ws);
  };
  
  ws.onclose = (event) => {
    console.log('Connection closed:', event.code);
    
    // Don't reconnect for permanent errors
    if (event.code === 4001 || event.code === 4002 || event.code === 4004) {
      console.error('Permanent error. Fix the problem before reconnecting.');
      return;
    }
    
    // Reconnect with exponential backoff
    setTimeout(() => {
      console.log(`Attempting to reconnect in ${reconnectDelay}ms...`);
      connect();
      reconnectDelay = Math.min(reconnectDelay * 2, maxDelay);
    }, reconnectDelay);
  };
  
  return ws;
}

function resubscribe(ws) {
  // Resubscribe to all channels you were subscribed to
  // Keep a list of active subscriptions
  const subscriptions = [
    { type: 'subscribe', channel: 'market', markets: ['market-id-1'] }
  ];
  
  subscriptions.forEach(sub => {
    ws.send(JSON.stringify(sub));
  });
}
```
