---
title: "Know when your app breaks before your users tell you"
description: "Capture every unhandled error, group it under a stable fingerprint, get alerted when a group is new or spiking, and send events to OpenTelemetry or Sentry."
section: "guides"
status: "Planned for 0.4"
spec: "error-reporting"
canonical: "https://mainsdk.dev/docs/guides/know-when-your-app-breaks"
updated: "2026-10-28"
---

# Know when your app breaks before your users tell you

> Capture every unhandled error, group it under a stable fingerprint, get alerted when a group is new or spiking, and send events to OpenTelemetry or Sentry.

Status: Planned for 0.4 · Canonical: https://mainsdk.dev/docs/guides/know-when-your-app-breaks · Updated: 2026-10-28

You will make an app capture every unhandled error, group it so one bug is one group, alert when a group is new in a release or spikes, and read the groups from the terminal. It takes about 10 minutes and needs no SDK from an error tracker.

## You need

- A MainSDK app with a `main.yaml`, behind one of the adapters (`mainsdk/hono`, `mainsdk/next` or `mainsdk/express`).
- Optional: an OpenTelemetry collector, or a Sentry project and its DSN.

## 1. Do nothing and read the groups

Errors are captured and grouped as soon as the adapter runs. Under `mainsdk dev` they are also written to the local event store:

```bash
npx mainsdk errors --since 1h
```

Each row is a fingerprint, a count, the last time it happened and whether it is new in this release.

## 2. Send the events somewhere

```yaml title="main.yaml"
network:
  allow: [o1.ingest.sentry.io]
logging:
  errors:
    driver: sentry
    dsn: secret:SENTRY_DSN
```

Use `driver: otlp` to send an OpenTelemetry exception event through `telemetry.otel` instead. Sending never delays a request: events wait in a bounded queue, and when the destination is down they are dropped with one `MAIN-REPORT-0003` record per outage. `mainsdk check` reports `MAIN-REPORT-0005` for a `sentry` driver with no `dsn` or a host missing from `network.allow`.

## 3. Get told about new and spiking errors

```yaml title="main.yaml"
logging:
  errors:
    alert:
      new: warning
      spike: { over: 50, per: 5m, severity: critical }
```

A group that first appears in this release raises `error:<fingerprint>` once across all instances when a `kv` section is declared. A group that passes 50 events in 5 minutes raises `error-spike:<fingerprint>` and resolves when the window empties. Both go through the routes you set in `alerts`.

## 4. Report browser errors

Set `logging.errors.browser: true`, then in the page:

```ts title="app/client.ts"
import { reportErrors } from "mainsdk/log/client";

reportErrors();
```

Reports are limited to 16 KB and 10 a minute per session or address, and the page's query and fragment are removed.

## What is never sent

Every event is redacted in process first: secret values, key formats, emails, tokens and phone numbers in the message, and file paths relative to the project. No request body, header, cookie, query value or environment value is read. A signed-in request adds only an opaque hash of the user id.

## Next

- [Logs, audit and telemetry](https://mainsdk.dev/docs/interfaces/log): the config keys, calls and codes.
- [Debug your app](https://mainsdk.dev/docs/guides/debugging): from a group to a fix.
