⚡ You're viewing a live demo of ChimerAI. Data resets daily at midnight UTC.Get the CLI →

Sentry Error Monitoring

ChimerAI ships with a ready-to-use Sentry integration for error tracking, performance monitoring, and session replay — covering browser, server, and edge runtimes out of the box.


Installation

npx chimerai add sentry

Files scaffolded

FilePurpose
sentry.client.config.tsBrowser error tracking + Session Replay
sentry.server.config.tsAPI routes + Server Components
sentry.edge.config.tsEdge Runtime (middleware)
instrumentation.tsNext.js hook — loads the right config per runtime
app/global-error.tsxGlobal error boundary with automatic Sentry reporting

Dependencies installed automatically:

@sentry/nextjs ^8.0.0

ChimerAI vs. Sentry Wizard

Sentry's own onboarding recommends running their interactive wizard:

# NOT needed when using ChimerAI
npx @sentry/wizard@latest -i nextjs --saas --org <org> --project <project>

Do not run the wizard in a ChimerAI app — it would overwrite the files ChimerAI already generated.

ChimerAI's chimerai add sentry produces the same output as the wizard, plus it is pre-wired to ChimerAI's auth and API conventions. The only steps the wizard does that ChimerAI does not automate are:

StepWizardChimerAI
Scaffold config files
Add @sentry/nextjs dependency
Add .env placeholders
Wrap next.config.js with withSentryConfig✅ automatic⚠️ manual (see below)
Create Sentry project on sentry.iobrowser flowmanual

In short: run chimerai add sentry, then follow the two manual steps in Setup below.


Setup

1. Create a Sentry project

Go to sentry.io → New Project → Next.js.

Copy the DSN from Settings → Client Keys (DSN).

2. Add environment variables

# .env.local
NEXT_PUBLIC_SENTRY_DSN=https://abc123@o123456.ingest.sentry.io/789
SENTRY_AUTH_TOKEN=sntrys_...      # Settings → Auth Tokens
SENTRY_ORG=your-org-slug
SENTRY_PROJECT=your-project-slug

SENTRY_AUTH_TOKEN is only needed for source map uploads during pnpm build. Without it, Sentry works but stack traces show minified code in production.

3. Wrap next.config.js (manual step)

// next.config.js
import { withSentryConfig } from '@sentry/nextjs';

const nextConfig = { /* your existing config */ };

export default withSentryConfig(nextConfig, {
  org: process.env.SENTRY_ORG,
  project: process.env.SENTRY_PROJECT,
  authToken: process.env.SENTRY_AUTH_TOKEN,
  hideSourceMaps: true,   // don't expose source maps in the browser bundle
  silent: !process.env.CI,
  disableLogger: true,
});

4. Test your setup

pnpm build && pnpm start

Open your app, trigger an error (see Testing), and check the Sentry dashboard.


How it works

Sentry is disabled in development by default (enabled: process.env.NODE_ENV === 'production'). This prevents your local dev noise from polluting your production error feed. All three configs follow this rule.

Browser crash       → sentry.client.config.ts  → Sentry Issues
API route throws    → sentry.server.config.ts  → Sentry Issues
middleware throws   → sentry.edge.config.ts    → Sentry Issues
Unhandled page err  → app/global-error.tsx     → Sentry Issues (+ "Something went wrong" UI)

ChimerAI-specific usage patterns

The scaffolded config catches all unhandled errors automatically. The patterns below are for adding context so errors are actionable — not just "something failed" but "gpt-4o rate-limited user abc@example.com during a RAG query."

Identify the current user

Add this once after a successful login — Sentry attaches user info to every subsequent event:

// e.g. in your SessionProvider or a useEffect after session load
import * as Sentry from '@sentry/nextjs';

if (session?.user) {
  Sentry.setUser({
    id: session.user.id,
    email: session.user.email ?? undefined,
  });
}

// On logout:
Sentry.setUser(null);

With this in place, every error in the Sentry dashboard shows which user was affected — essential for Enterprise support workflows.


AI provider errors

The chat stream route is the highest-value place to add Sentry context. Provider rate limits, token overflows, and API outages all surface here:

// app/api/v1/chat/stream/route.ts
import * as Sentry from '@sentry/nextjs';

try {
  // ... your existing streaming logic
} catch (error) {
  Sentry.withScope((scope) => {
    scope.setTag('provider', provider.type);        // 'openai' | 'anthropic' | 'ollama'
    scope.setTag('model', modelId);                 // 'gpt-4o' | 'claude-3-5-sonnet'
    scope.setExtra('userId', auth.userId);
    scope.setExtra('conversationId', conversationId);
    Sentry.captureException(error);
  });
  // re-throw or return error response as usual
  throw error;
}

This lets you filter in Sentry by provider or model — for example "show me all errors from Anthropic in the last 24h."


Provider sync failures

When a provider sync fails (network error, invalid API key, rate limit), capture with context:

// app/api/providers/[id]/sync/route.ts
import * as Sentry from '@sentry/nextjs';

try {
  // ... sync logic
} catch (error) {
  Sentry.withScope((scope) => {
    scope.setTag('provider_type', provider.type);
    scope.setExtra('provider_id', provider.id);
    scope.setLevel('warning');  // sync failure is annoying, not critical
    Sentry.captureException(error);
  });
  return NextResponse.json({ error: 'Sync failed' }, { status: 500 });
}

Billing webhook failures

Missed webhooks from LemonSqueezy or Stripe mean subscriptions don't activate. These should be errors, not warnings:

// app/api/billing/webhook/route.ts
import * as Sentry from '@sentry/nextjs';

try {
  // ... webhook processing
} catch (error) {
  Sentry.withScope((scope) => {
    scope.setTag('billing_provider', 'lemonsqueezy'); // or 'stripe'
    scope.setTag('webhook_event', event.type);
    scope.setExtra('subscription_id', event.data?.id);
    scope.setLevel('error');
    Sentry.captureException(error);
  });
  // Return 500 so LemonSqueezy retries the webhook
  return NextResponse.json({ error: 'Webhook failed' }, { status: 500 });
}

Why this matters: If you return 200 from a failed webhook handler, the billing provider won't retry. Return 500 so you get a retry AND a Sentry alert.


RAG pipeline errors

Embedding generation and vector search can fail silently. Make failures visible:

// app/api/v1/rag/query/route.ts
import * as Sentry from '@sentry/nextjs';

try {
  const chunks = await vectorSearch(query, sessionId);
  // ...
} catch (error) {
  Sentry.withScope((scope) => {
    scope.setTag('rag_stage', 'vector_search'); // or 'embedding_generation'
    scope.setExtra('query_length', query.length);
    scope.setExtra('session_id', sessionId);
    Sentry.captureException(error);
  });
  // Graceful fallback: answer without context
  return streamWithoutContext(messages);
}

Non-error tracking with captureMessage

Not every notable event is an exception. Use captureMessage for important state changes you want visibility into:

import * as Sentry from '@sentry/nextjs';

// Admin actions worth auditing in Sentry
Sentry.captureMessage('Provider API key rotated', {
  level: 'info',
  tags: { provider: provider.type },
  extra: { provider_id: provider.id, changed_by: session.user.email },
});

// Soft limits hit (not errors, but worth knowing)
Sentry.captureMessage('User approaching credit limit', {
  level: 'warning',
  extra: { userId, creditsRemaining: balance },
});

Levels: debuginfologwarningerrorfatal


Filtering noise

Not every error deserves an alert. Configure beforeSend in sentry.client.config.ts to drop known non-issues:

// sentry.client.config.ts
Sentry.init({
  dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
  // ...
  beforeSend(event, hint) {
    const error = hint?.originalException;

    // Ignore user-canceled fetch requests (e.g. navigating away mid-stream)
    if (error instanceof Error && error.message === 'The user aborted a request.') {
      return null;
    }

    // Ignore known Next.js hydration warnings
    if (event.message?.includes('Hydration failed')) {
      return null;
    }

    return event;
  },
});

On the server side, add similar filters to sentry.server.config.ts — for example ignoring 404s:

// sentry.server.config.ts
beforeSend(event) {
  // Don't alert on 404 Not Found
  if (event.contexts?.response?.status_code === 404) {
    return null;
  }
  // Strip auth headers (already in the scaffold — keep this)
  if (event.request?.headers) {
    delete event.request.headers['authorization'];
    delete event.request.headers['cookie'];
  }
  return event;
},

Setting up alerts

In the Sentry dashboard → Alerts → Create Alert. Recommended rules for ChimerAI apps:

AlertConditionSuggested threshold
AI provider downtag:provider errors spike> 10 errors in 5 min
Billing webhook failedtag:billing_provider errorsAny single occurrence
Global error rate spikeAll errors combined> 50 errors in 10 min
New issueFirst occurrence of any new issueImmediately (useful in early production)

Set the notification channel to email or Slack under Settings → Integrations.


Session Replay

Session Replay records what the user was doing when an error occurred — clicks, scrolls, network requests. It's configured in sentry.client.config.ts:

replaysSessionSampleRate: 0.1,   // record 10% of all sessions
replaysOnErrorSampleRate: 1.0,   // record 100% of sessions with errors

Privacy: Replay automatically masks all <input> fields. For additional masking (e.g. chat messages you don't want recorded):

// Add data attribute to sensitive elements
<div data-sentry-mask>
  {message.content}
</div>

View replays in Sentry → Replays. Click any error in Issues → "View Replay" to see exactly what the user did.


Testing

To verify Sentry is working without deploying to production, temporarily enable it in development:

// sentry.client.config.ts — temporary test change
enabled: true,  // revert after testing!

Then trigger a test event:

// In any Client Component or Browser DevTools console:
import * as Sentry from '@sentry/nextjs';
Sentry.captureMessage('Sentry test — delete me', 'info');

Check Sentry dashboard → Issues → the test event should appear within ~30 seconds.

Remember to revert enabled: true before committing.


Source maps in production

Source maps allow Sentry to show readable stack traces (original TypeScript line numbers) instead of minified bundle offsets. They are uploaded during pnpm build when SENTRY_AUTH_TOKEN is set.

Without source maps:  at r (/_next/static/chunks/app/page-abc123.js:1:4892)
With source maps:     at ChatPage (app/dashboard/chat/page.tsx:47:12)

For Vercel deployments, add all four Sentry env vars to your Vercel project settings (Settings → Environment Variables). Vercel runs pnpm build in CI where SENTRY_AUTH_TOKEN is available, so maps upload automatically on every deploy.


Further reading

ChimerAI Docs · Back to Demo