When something breaks. Pages mirror the failure modes in Observability, but with concrete commands and decision trees.
Severity legend. P1 = customer-visible outage. P2 = degraded experience. P3 = internal tooling broken but public site healthy.
/blogs/* first.Symptom: User authenticates → bounced back to /auth/login.
Domain
must be exactly .matters.ai (note the leading dot).apps/workspace/proxy.ts is matching the path. The
isPublicRoute matcher should be ["/auth(.*)", "/api/webhooks/clerk(.*)", "/api/health"].matters-workspace. The middleware bundle sometimes ships stale./api/revalidate. Did the webhook arrive?
curl -X POST https://matters.ai/api/revalidate \
-H "Content-Type: application/json" \
-H "x-webhook-secret: $WORDPRESS_WEBHOOK_SECRET" \
-d '{"contentType":"post","slug":"<the-stale-slug>"}'
WORDPRESS_WEBHOOK_SECRET in Vercel against
the WordPress plugin settings.https://matters.ai/<path>?_=$(date +%s) to bust the URL cache; if still stale, file
Vercel support.Symptom: /api/workspace/webinars/email/bulk-invite reports failed > 0.
getAuditLogs({ eventType: "webinars.bulk-invite", limit: 1 });
metadata field has { test_mode, sent, failed, total }.[bulk-invite] errors in the same time window. Most likely:
AWS SES bounce / sandbox-mode limit.Message-ID, so duplicates won't double-send.getAuditLogs({ eventType: "webinars.sync-salesforce", limit: 1 }).metadata.failed count and individual failures[] in the response.SALESFORCE_* env vars in
Vercel.SALESFORCE_DIAL_CODE_FIELD_ID.concurrency: 1 or 2).Symptom: A super-admin gets a 429 on a route they should be able to call freely.
eventType: rate_limit_exceeded for the user.<action>:<userId> — they'll need to wait for reset (an epoch ms in
the response).Symptom: audit log shows eventType: permission_escalation_attempt or user_role_changed
where the actor is not a super-admin.
audit_logs for any other actions by the same userId in the last 24h. Cross-
reference with Sentry for related errors.#security-incidents, severity P1. Notify legal + super-admin within 1
hour. Send a written timeline within 24h.Symptom: build fails with ENOSPC: no space left on device.
This is a local-development trap more than a Vercel issue — Vercel's build agents are clean per run. But locally:
rm -rf .next apps/workspace/.next apps/webdocs/.next labs/.next
rm -rf node_modules/.cache labs/node_modules/.cache
The labs/ sibling app's .next is the usual culprit (~700MB).
Open .github/workflows/ci.yml. The pipeline runs:
pnpm-lock.yaml).pnpm run lint:error, currently continue-on-error: true due to pre-existing debt).If the workspace build fails on Clerk prerender, the dummy pk_test_* key in
.github/workflows/ci.yml isn't passing Clerk's format validator. Update to a longer
realistic-looking dummy.
Symptom. Visitors submit a gated form and see "Check your inbox", but nothing arrives; or,
after 2026-09-03, the datasheet form shows "We couldn't email your datasheet right now"
(HTTP 502 from /api/datasheets/submit). Sentry fills with feature:email warnings
("Email primary provider failed — using fallback") or feature:datasheet-download errors
("failed on every provider").
Severity. P1 — every lead-capture flow on the marketing site delivers by email. Revenue-facing.
Background. lib/email/index.ts sends through the primary (EMAIL_PROVIDER: ses / smtp
/ resend) and, on any failure, retries once through the backup (EMAIL_FALLBACK_PROVIDER,
default Resend from resources.matters.ai). Policy: Resend is always the backup. On
2026-09-03 SES stopped delivering and there was no second path — every mail on the site went dark.
Decision tree.
feature:email. tags.primary tells you which engine is failing;
extra.error carries the provider's message (SES: MessageRejected, Throttling,
AccountSuspended; SMTP: EAUTH, ECONNECTION).
datasheet-download errors ⇒ the backup is carrying traffic. Mail is
flowing. Fix the primary at leisure (step 3), but do not leave it: Resend quotas are sized as
a backup, not the primary.failed on every provider ⇒ both engines down. Go to step 2 immediately.RESEND_API_KEY set, EMAIL_FALLBACK_PROVIDER unset or resend. If the key is missing,
add it and redeploy — that alone restores delivery. Confirm resources.matters.ai shows
Verified in the Resend dashboard (Domains).SES_SETUP.md → "Deliverability
thresholds"), quota exhaustion, a rotated IAM key (AWS_SES_ACCESS_KEY_ID /
SMTP_PASS), or the sending identity no longer verified (AWS_SES_FROM_EMAIL).EMAIL_PROVIDER=resend in Vercel and redeploy. Revert once SES is healthy.200 with
delivery: "email" on success and 502 with the visitor-facing message on total failure. The
route logs provider and fellBack for the send.Escalation. Both providers failing for more than 15 minutes, or SES showing account under review: page the on-call owner of the AWS account. Reputation suspensions need a human reply to AWS and cannot be fixed by redeploying.
When you debug a production incident, take 30 minutes after the fix to write the runbook here. Format:
Future-you will thank present-you.