> For the complete documentation index, see [llms.txt](https://dnotifier.gitbook.io/product-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://dnotifier.gitbook.io/product-docs/operations/troubleshooting.md).

# Troubleshooting

Production playbooks for the most common DNotifier SDK issues. Each section lists symptoms, likely causes, and step-by-step fixes.

***

## Connection failures

### Symptoms

* `connect()` throws or rejects
* `onConnected` never fires
* Socket opens then immediately closes
* `isConnected` stays `false`

### Likely causes

| Cause                                       | Fix                                                            |
| ------------------------------------------- | -------------------------------------------------------------- |
| Missing required constructor fields         | Provide `appId`, `secret`, `transport`, `userId`               |
| Node.js without `WebSocketImpl`             | Pass `WebSocketImpl: WebSocket` from the `ws` package          |
| Network / firewall blocks `wss://`          | Allow outbound TLS to `api.dnotifier.com`                      |
| Corporate proxy                             | Configure proxy for WebSocket or run from unrestricted network |
| Called `send()` before `connect()` finished | `await notifier.connect()` first                               |
| Invalid custom `url`                        | Remove override or fix URL; use `wss://` in production         |

### Diagnostic steps

1. Log the exact error from `connect()` catch block
2. Verify credentials in [app.dnotifier.com](https://app.dnotifier.com)
3. Run minimal connect script from [Debugging](/product-docs/operations/debugging.md)
4. In browser: DevTools → Network → WS — check close code and reason
5. Confirm transport: `ws` for realtime, `http` for AI-only (no socket expected)

### Node.js quick fix

```js
import WebSocket from "ws";

const notifier = new DNotifier({
  appId: process.env.DNOTIFIER_APP_ID,
  secret: process.env.DNOTIFIER_SECRET,
  transport: "ws",
  userId: "user-1",
  WebSocketImpl: WebSocket, // required in Node
  onConnected: () => {},
  onMessage: () => {},
  onDisconnected: () => {},
});
```

→ [Connection lifecycle](/product-docs/realtime-communication/connection-lifecycle.md) · [Node.js platform guide](/product-docs/platform-guides/nodejs.md)

***

## Auth 400 — authentication failed

### Symptoms

* Error message contains `Authentication Failed` or HTTP 400 from auth endpoint
* `connect()` fails before WebSocket opens
* `authToken` is null or undefined

### Likely causes

| Cause                               | Fix                                                 |
| ----------------------------------- | --------------------------------------------------- |
| Wrong **secret**                    | Copy fresh secret from dashboard; redeploy env vars |
| Wrong **appId**                     | Match app ID exactly (no extra spaces)              |
| Dev credentials in production       | Create separate production app                      |
| Secret rotated but deployment stale | Update all running instances                        |
| Empty env vars                      | `echo $DNOTIFIER_SECRET` — must not be blank        |

### Diagnostic steps

1. Open [app.dnotifier.com](https://app.dnotifier.com) → your app → verify App ID and secret
2. Rotate secret if unsure; update deployment immediately
3. Test with hard-coded values **only in local terminal** (never commit)
4. For HTTP transport, auth uses the same endpoint — failure is not WebSocket-specific

{% hint style="warning" %}
A 400 auth error is almost always **credentials**, not a SDK bug. Fix `appId` / `secret` before investigating further.
{% endhint %}

→ [Credentials & environment](/product-docs/getting-started/credentials.md) · [Security best practices](/product-docs/operations/security.md)

***

## AI not enabled

### Symptoms

* `aiEnabled` is `false` after `connect()`
* `sendAI()` fails or returns an error
* `getPlanLimits()` shows AI disabled

### Likely causes

| Cause                             | Fix                                                            |
| --------------------------------- | -------------------------------------------------------------- |
| Plan does not include AI          | Upgrade plan at [app.dnotifier.com](https://app.dnotifier.com) |
| Wrong app (free/staging tier)     | Confirm app under correct account and plan                     |
| Using `ws` transport for `sendAI` | Switch to `transport: "http"` for AI calls                     |
| Monthly quota exhausted           | Check dashboard usage; wait for reset or upgrade               |

### Diagnostic steps

```js
await notifier.connect();
console.log("aiEnabled:", notifier.aiEnabled);
console.log("limits:", notifier.getPlanLimits());
```

```dart
await notifier.connect();
print('aiEnabled: ${notifier.aiEnabled}');
print('limits: ${notifier.getPlanLimits()}');
```

1. If `aiEnabled: false` — plan issue, not code
2. If `aiEnabled: true` but `sendAI` fails — check transport is `http` and error message for quota
3. Gate UI features on `aiEnabled` to avoid user-facing errors

→ [AI overview](/product-docs/ai/overview.md) · [Pricing & plans](/product-docs/platform-overview/pricing.md)

***

## Message not received

### Symptoms

* `send()` resolves without error
* Sender sees success; receiver's `onMessage` never fires
* Chat appears one-way

### Likely causes

| Cause                              | Fix                                                      |
| ---------------------------------- | -------------------------------------------------------- |
| Receiver not connected             | Receiver must `await connect()` with `transport: "ws"`   |
| Wrong `receiverId`                 | IDs must match exactly — check spelling and prefix rules |
| Receiver using HTTP transport      | HTTP does not push to `onMessage` — use `ws` on receiver |
| Same `userId` typo on both sides   | Confirm sender's `receiverId` equals receiver's `userId` |
| Receiver callback not registered   | Set `onMessage` before `connect()`                       |
| Message filtered in app code       | Log raw `onMessage` before routing logic                 |
| Chunk reassembly still in progress | Wait for full payload on large messages                  |

### Diagnostic steps

1. **Sender**: log `{ senderId, receiverId, data.type }` on every send
2. **Receiver**: log every `onMessage` at the top of the handler
3. Connect two clients with distinct `userId` values in a test script
4. Send minimal text: `{ type: "text", text: "ping" }`
5. Verify both use `transport: "ws"` for realtime delivery

{% hint style="info" %}
DNotifier routes by explicit user ID. There is no shared channel — if `receiverId` does not match a connected client's `userId`, no delivery occurs.
{% endhint %}

→ [Send & receive text](/product-docs/realtime-communication/send-and-receive.md) · [Understanding messages](/product-docs/getting-started/understanding-messages.md)

***

## Workflow errors

### Symptoms

* `runWorkflow()` throws
* `WorkflowError` with validation message
* Workflow runs but `result` is undefined
* No `executionId` in dashboard

### Likely causes

| Cause                                      | Fix                                                                         |
| ------------------------------------------ | --------------------------------------------------------------------------- |
| Agent not registered                       | Call `.registerAgents({ ... })` before `runWorkflow`                        |
| Wrong agent name in `ctx.runAgent()`       | Name must match `defineAgent({ name })`                                     |
| `transport: "ws"`                          | Use `transport: "http"` for workflows                                       |
| Not connected                              | `await notifier.connect()` before `runWorkflow`                             |
| Uncaught exception in agent `run`          | Wrap agent logic in try/catch; error propagates as workflow failure         |
| `observability: true` but no `executionId` | Confirm `connect()` succeeded and network access to the production API host |

### Diagnostic steps

```js
try {
  const run = await notifier.runWorkflow({
    workflow,
    input: "test input",
  });
  console.log(run.executionId, run.result, run.state);
} catch (err) {
  console.error(err.name, err.message);
}
```

1. Validate workflow structure: `entry` function, registered agents
2. Run minimal one-agent workflow in isolation
3. Enable `observability: true` and search dashboard by workflow name
4. Inspect `WorkflowError` message for missing agent or invalid step

### Minimal working workflow

```js
const agent = DNotifier.defineAgent({
  name: "echo",
  async run(ctx) {
    return { echo: ctx.input };
  },
});

const workflow = new DNotifier.Workflow({
  name: "echo-test",
  async entry(ctx) {
    return ctx.runAgent("echo");
  },
}).registerAgents({ echo: agent });

await notifier.connect();
const run = await notifier.runWorkflow({ workflow, input: "hello" });
```

→ [Workflows overview](/product-docs/workflows-and-agents/overview.md) · [Define an agent](/product-docs/workflows-and-agents/define-agent.md)

***

## Other common issues

| Issue                                  | Quick fix                                                 |
| -------------------------------------- | --------------------------------------------------------- |
| `No WebSocket implementation provided` | Add `WebSocketImpl` (Node) or run in browser              |
| `WebSocket not connected` on send      | Await `connect()`; handle disconnect/reconnect            |
| Chat history empty                     | Call `fetchChatHistory`; response arrives via `onMessage` |
| Large image never displays             | Wait for chunk reassembly; check `messageSizeLimit`       |
| Duplicate messages in UI               | Deduplicate by `msg.metadata.id`                          |

***

## When to contact support

Gather before contacting support:

* SDK language and version (npm / pub.dev)
* Transport (`ws` or `http`)
* Redacted error message and stack trace
* Whether auth succeeds (`authToken` present)
* `getPlanLimits()` output
* Timestamp and app ID (never the secret)

→ [Support & links](/product-docs/appendix/support.md)

***

## Related guides

* [Debugging](/product-docs/operations/debugging.md)
* [FAQ](/product-docs/operations/faq.md)
* [Production checklist](/product-docs/operations/production-checklist.md)
