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

# Argus Troubleshooting: Missing Events, DSN, and 4xx Errors

> Diagnose and resolve common Argus integration problems — missing events, invalid DSN, HTTP 401/429/400 responses, and missing stack traces.

This guide walks you through the most common problems you'll encounter when integrating Argus into your application. For each issue you'll find a clear cause and the exact steps to fix it — start at the top and work down until your events appear in the dashboard.

<AccordionGroup>
  <Accordion title="Errors are not appearing in the dashboard">
    Work through this checklist in order — the first item is the most common cause.

    **1. Call `init()` before anything else**

    `init()` must be the very first statement in your application's entry file. If any error fires before `init()` runs, the SDK isn't listening yet and the event is lost.

    ```ts theme={null}
    // ✅ Correct — init() is first
    import { init } from "@argusdev/sdk-node";
    init({ dsn: "https://PUBLIC_KEY@your-domain.com/PROJECT_ID" });

    // the rest of your app starts here
    import "./server";
    ```

    **2. Verify your DSN**

    Open your project's Settings page, copy the DSN, and confirm it matches the format below exactly — including the `https://` scheme, the public key before `@`, and the project ID in the path.

    ```
    https://PUBLIC_KEY@your-domain.com/PROJECT_ID
    ```

    **3. Check network reachability**

    Confirm that your application can reach the Argus API host. Firewall rules, VPNs, or restrictive Content Security Policies (in the browser) can silently block outbound POST requests to the ingest endpoint.

    **4. Check for swallowed errors in development**

    If you wrap code in `try/catch` and never re-throw, the SDK never sees the error. Make sure exceptions bubble up or call `captureException(err)` explicitly inside your catch block.

    **5. Inspect the network request**

    Open your browser DevTools **Network** tab (or a tool like `curl` for Node.js) and look for a POST request to `/api/v1/ingest/<projectId>/envelope`. Check the HTTP response code:

    | Response   | Meaning                                                            |
    | ---------- | ------------------------------------------------------------------ |
    | `200`      | Event accepted — check the dashboard in a few seconds.             |
    | `401`      | DSN public key doesn't match the project.                          |
    | `429`      | Quota or rate limit exceeded.                                      |
    | `400`      | Envelope payload is malformed.                                     |
    | No request | `init()` wasn't called, or a CSP/firewall is blocking the request. |
  </Accordion>

  <Accordion title="Invalid DSN error at startup">
    `init()` calls `parseDsn()` immediately and **throws** if the DSN is malformed — this is intentional so you catch misconfiguration at startup rather than silently losing events in production.

    The error message tells you exactly what's wrong:

    | Error message                   | Fix                                                        |
    | ------------------------------- | ---------------------------------------------------------- |
    | `not a valid URL`               | The DSN isn't a URL at all — check for missing `https://`. |
    | `missing public key before '@'` | Add the public key between `://` and `@`.                  |
    | `missing project id in path`    | Add the project ID at the end of the URL path.             |
    | `protocol must be http(s)`      | Use `https://` (or `http://` for local development only).  |

    **Correct DSN format:**

    ```
    https://PUBLIC_KEY@your-domain.com/PROJECT_ID
          ↑             ↑              ↑
          scheme       public key     project ID
    ```

    Copy the DSN directly from **Project Settings → DSN** to avoid manual typos. Do not add trailing slashes or extra path segments.
  </Accordion>

  <Accordion title="HTTP 401 responses from the ingest endpoint">
    A `401` means the public key in your DSN doesn't match the project you're posting to. The Argus API validates the key on every ingest request.

    **Common causes and fixes:**

    * **Wrong project DSN** — each project has its own unique DSN. Open **Project Settings** for the project you want to track and copy its DSN directly. Don't reuse the DSN from a different project.
    * **Stale DSN** — if the DSN has been regenerated since you last configured the SDK, update `init()` with the new value.
    * **Environment variable not loaded** — if you read the DSN from an environment variable, confirm the variable is actually set in the current environment (`console.log(process.env.ARGUS_DSN)` as a quick sanity check, then remove it).
  </Accordion>

  <Accordion title="HTTP 429 responses (quota or rate limit exceeded)">
    A `429` means one of two things: your organization has exhausted its **monthly event quota**, or you've exceeded the **per-second rate limit** for a single project.

    **What the SDK does on 429**

    The SDK drops the event immediately and does not retry — retrying a quota-exceeded endpoint would only make the situation worse. No error is thrown into your application; a `console.warn` is emitted instead.

    **How to resolve it**

    1. Open the **Usage** page in your Argus dashboard to see your current monthly event count and your plan limit.
    2. If you've hit your monthly quota:
       * **Free plan (10,000 events/month):** Upgrade to Pro for a 500,000 event limit, or wait for the quota to reset at the start of the next calendar month.
       * **Pro plan (500,000 events/month):** Contact support if you need a higher limit.
    3. If you're hitting the per-second rate limit, consider sampling high-volume events before they reach `captureException()`.
  </Accordion>

  <Accordion title="HTTP 400 responses from the ingest endpoint">
    A `400` means the envelope payload failed schema validation. The Argus ingest validator enforces a strict contract.

    **Most common causes:**

    | Problem                                               | Fix                                                                                                                                                                                                                                        |
    | ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
    | `timestamp` is in **seconds** instead of milliseconds | Use `Date.now()` — never `Math.floor(Date.now() / 1000)`. The validator requires a value of at least `1_577_836_800_000` (2020-01-01 in ms). A seconds-format timestamp (\~1.7e9) is roughly 1,000× too small and is rejected immediately. |
    | Missing `exception.stacktrace.frames` array           | Include at least one stack frame object in the `frames` array.                                                                                                                                                                             |
    | Zero stack frames                                     | The `frames` array must have at least one entry.                                                                                                                                                                                           |

    **If you're using the official SDK**

    The official `init()` and `captureException()` APIs always produce valid envelopes — including synthesizing a placeholder frame when no stack is available. If you're seeing `400` with the official SDK, open an issue on the Argus repository with the exact error response body.

    **If you're building a custom integration**

    Ensure your envelope matches this structure, and that `timestamp` is always produced with `Date.now()`:

    ```json theme={null}
    {
      "timestamp": 1700000000000,
      "exception": {
        "type": "Error",
        "value": "Something went wrong",
        "stacktrace": {
          "frames": [
            { "filename": "app.js", "function": "handleRequest", "lineno": 42, "colno": 7 }
          ]
        }
      }
    }
    ```
  </Accordion>

  <Accordion title="Stack traces are missing or incomplete">
    **Cross-origin scripts (browser)**

    Browsers intentionally redact stack traces for errors originating from scripts loaded from a different origin. The `window.onerror` handler receives only `"Script error."` with no filename, line, or column.

    Fix: host your scripts on the same origin as your page, or add the following to the `<script>` tag and ensure the script's server returns `Access-Control-Allow-Origin: *`:

    ```html theme={null}
    <script src="https://cdn.example.com/app.js" crossorigin="anonymous"></script>
    ```

    **Minified JavaScript without source maps**

    If you deploy minified code without source maps, stack frames reference minified filenames and one-character function names. Source map resolution is on the Argus roadmap — until it ships, deploy with source maps enabled in your bundler, or keep unminified builds in non-production environments where you use Argus.

    **React render errors**

    React swallows errors that occur during the render phase — they don't reach `window.onerror`. Use `<ArgusErrorBoundary>` from `@argusdev/sdk-react` to capture them:

    ```tsx theme={null}
    import { ArgusErrorBoundary } from "@argusdev/sdk-react";

    function App() {
      return (
        <ArgusErrorBoundary>
          <YourApp />
        </ArgusErrorBoundary>
      );
    }
    ```
  </Accordion>

  <Accordion title="Node.js process exits unexpectedly after an uncaught error">
    This is expected behavior. When the Node.js SDK captures an `uncaughtException`, it sends the event to Argus and then calls `process.exit(1)`.

    This matches what Node.js itself does without Argus — after an uncaught exception the process is in an undefined state and Node's own documentation recommends exiting. Argus doesn't change this behavior; it simply captures the event and waits for the network send to complete before the process exits so the event is not lost.

    **`unhandledRejection` behaves differently** — the SDK captures and sends the event but does **not** exit, because unhandled promise rejections don't necessarily leave the process in a bad state.

    If you need the process to stay alive after an uncaught exception (for example, in a supervised worker), catch the error explicitly and call `captureException(err)` manually instead of relying on the global hook.
  </Accordion>

  <Accordion title="Express errors are not being captured">
    The Argus Express error handler must be registered **after all your routes and other middleware — it must be the very last `app.use()` call in your application**. Express passes errors to error-handling middleware in registration order, so placing `argusErrorHandler()` too early means it never receives errors thrown by your route handlers.

    ```ts theme={null}
    import express from "express";
    import { init, argusErrorHandler } from "@argusdev/sdk-node";

    init({ dsn: "https://PUBLIC_KEY@your-domain.com/PROJECT_ID" });

    const app = express();

    // ✅ Register all your routes first
    app.get("/", (req, res) => res.send("Hello"));
    app.use("/api", apiRouter);

    // ✅ Your own error handler (if any) goes before argusErrorHandler
    app.use((err, req, res, next) => {
      res.status(500).json({ error: "Internal Server Error" });
      next(err);
    });

    // ✅ argusErrorHandler() must be the very last app.use() call
    app.use(argusErrorHandler());

    app.listen(3000);
    ```

    `argusErrorHandler()` must come last — after any custom error handlers — so that every error, including those that pass through your own handlers, is captured before the request cycle ends.
  </Accordion>
</AccordionGroup>
