# Error Handling

Learn how to handle errors and debug issues in your **Tode analytics** implementation for Figma plugins and widgets.

## Silent Failures by Design

Tode methods are designed to **fail silently** to avoid disrupting your plugin's functionality. This means:

- Tracking calls won't throw errors that crash your UI
- Users won't see error messages from analytics
- Your plugin continues working even if analytics fail

## Debug Mode

Enable debug mode during development to see what's happening under the hood. This logs all tracking calls and any errors to the console.

```typescript title="code.ts"
import { tode } from '@tode-sdk/core';

await tode.init({
  apiKey: 'your-api-key',
  debug: true  // Enable for development
});
```

With debug mode enabled, you'll see console logs for:
- Initialization status
- Each tracking call
- Connection state changes
- Any errors that occur

**Tip:** Disable debug mode in production to keep the console clean for your users.

```typescript title="code.ts"
await tode.init({
  apiKey: 'your-api-key',
  debug: process.env.NODE_ENV === 'development'
});
```

---

## Common Issues

| Issue | Cause | Solution |
|-------|-------|----------|
| Tracking not working | `init()` was never called, so events stay queued | Call `init()` in code.ts |
| No session data | WebSocket not connecting | Check network access settings in manifest.json |
| `isReady` always false | Config not received | Ensure `init()` is called after `showUI()` |
| Events not appearing | Network blocked | Verify allowed domains in manifest.json |
| Users count stays at zero | `currentuser` permission missing | Add `"permissions": ["currentuser"]` to manifest.json |
| Analytics silent in a template project | `TODE_API_KEY` empty in `.env` | Copy `.env.example` to `.env`, set the key, rebuild |
| Console shows `429` | Monthly event quota used up | Check usage on the dashboard; upgrade or wait for the period to reset |
| Console shows `403 event_types_limit_reached` | Too many distinct `actionName`s | Remove a type in plugin settings or upgrade ([Plans and Limits](https://docs.usetode.dev/plans)) |

---

## Server Responses

Every tracking request answers with JSON. Success is `201 {"ok": true}`. Errors carry an `error` code and a human-readable `message`:

| Status | `error` | Meaning | What to do |
|--------|---------|---------|------------|
| `400` | `invalid_body` | A required field is missing or has the wrong type; `message` names it | Update the SDK; the adapters always send a valid body |
| `401` | `api_key_required` | No `X-API-Key` header | Pass `apiKey` to `init()` |
| `403` | `invalid_api_key` | Unknown or revoked key | Copy the key from the plugin settings; rotated keys stop working after 24 hours |
| `403` | `plugin_suspended` | The plugin exceeds the account's plan | Upgrade or archive other plugins |
| `403` | `event_types_limit_reached` | New `actionName` beyond the plan's cap; existing names still work | Remove a type or upgrade |
| `429` | `events_limit_reached` | Monthly quota used up | Upgrade or wait for the reset |
| `429` | `rate_limited` | More than 600 requests per minute from one key | Debounce bursts; `Retry-After` says when |
| `429` | `ip_rate_limited` | More than 120 requests per minute from one IP address | Debounce bursts; `Retry-After` says when |
| `429` | `ip_limit_reached` | More than 20,000 events in a day from one IP address | Expected only from abuse of a leaked key; rotate the key if it is not you |
| `429` | `user_limit_reached` | One Figma user sent more than 2,000 events in a day (200 without an open plugin UI session) | Real usage stays far below this; rotate the key if the traffic is not yours |

The SDK logs these to the console and continues; your plugin never sees an exception.

---

## Network Configuration

Make sure your `manifest.json` includes the required domains and the `currentuser` permission:

```json title="manifest.json"
{
  "permissions": ["currentuser"],
  "networkAccess": {
    "allowedDomains": [
      "https://processing.usetode.dev",
      "wss://processing.usetode.dev"
    ]
  }
}
```

Missing network access is the most common cause of tracking failures. A missing `currentuser` permission does not stop events, but `figma.currentUser` is `null`, so every event is anonymous and the dashboard shows no unique users.

---

## Session Connection

Session length comes from a WebSocket the UI adapter keeps open. If it drops, the adapter reconnects on its own: after 1s, 2s, 4s and so on, up to 30s between tries, for as long as the UI is open. When the browser reports the network is back it retries at once, so a plugin left open through laptop sleep picks up again.

Each reconnect is stored as a separate session. Read `wsState` (`disconnected`, `connecting`, `connected`, `error`) if you want to show the connection in your UI. Socket errors reach the console only with `debug` on.

---

## Checking Ready State

You can track before `isReady` is `true`. The SDK holds up to 50 early events and sends them when the config arrives from the plugin controller:

```typescript
// In your UI code, no ready check needed
tode.trackAction('button_clicked');
```

The UI also asks the controller for the config when it starts listening, so a slow-loading UI, or one you close and open again with `figma.showUI()`, still becomes ready. Your own `figma.ui.onmessage` handler will see that request as `{ type: 'TODE_UI_READY' }`; ignore message types you don't handle.

If `isReady` is always `false`:
1. Verify `tode.init()` is called in your plugin controller
2. Check that `init()` is called after `figma.showUI()`
3. Enable debug mode to see initialization logs
4. Verify network access is configured correctly

---

## Getting Help

If you're still experiencing issues:

- Review the [Best Practices](https://docs.usetode.dev/best-practices) for correct implementation patterns
- Check your framework guide for specific setup instructions
- Enable debug mode and check browser console for errors
- Write to [hello@usetode.dev](mailto:hello@usetode.dev) with your debug logs

Source: https://docs.usetode.dev/error-handling
