Troubleshooting
Common failure modes and their diagnostic order.
Containers crash on first boot
Section titled “Containers crash on first boot”docker compose -f docker/docker-compose.yml logs apiMost failures are missing env vars or secrets shorter than 32 bytes. The API prints exactly which knob is wrong before exiting.
Migrations fail
Section titled “Migrations fail”The API tries migrations on every boot. A failed migration logs the exact statement and stops the container. Common causes:
- A previous deploy crashed mid-migration. Inspect
goose_db_version, manually re-apply the failed statement if it’s idempotent, otherwise restore from the last clean backup. - You rolled a binary back across a destructive schema change. Pulse doesn’t ship destructive migrations, but if you’ve forked, check your own.
Alerts not firing
Section titled “Alerts not firing”In order:
- Settings → Channels → <channel> → Send test. If the test fails, the channel is wrong (bad URL, revoked token).
- Alerts → <rule>. Confirm the monitor selector actually matches a monitor, and the condition triggers (e.g., 3 consecutive failures must have happened).
- Audit log. Every alert fire is recorded. If it’s there, the channel got the payload — debug downstream.
/metrics.pulse_alerts_fired_total{rule_id="..."}increments per fire. If the counter moves but no notification arrives, the channel ate the request.
Public status page shows the wrong status
Section titled “Public status page shows the wrong status”The page derives status from linked monitors. If you see operational but a monitor is down:
- Confirm the monitor is linked to a component on this page.
- Confirm the component’s “Show on public page” toggle is on (default true).
Custom domain stuck “pending”
Section titled “Custom domain stuck “pending””The TXT record exists but verify fails:
- DNS may be propagating; wait 5–15 minutes.
- Some providers ship the record at
_pulse-challenge.<sub>.<root>.<custdomain>instead of_pulse-challenge.<sub>.<custdomain>. The record name must include the full status-page subdomain, not just the apex. - DNS-over-HTTPS resolvers (Cloudflare 1.1.1.1) sometimes lag behind authoritative. Pulse resolves via the system resolver; if you’ve overridden
resolv.conf, that’s what answers.
Status page is the wrong theme
Section titled “Status page is the wrong theme”The theme picker honours, in order:
?theme=query param on the URL.- Per-page
themesetting (Auto / Light / Dark). - Visitor’s
prefers-color-scheme.
If a customer is seeing light when you expect dark, force ?theme=dark to confirm the per-page setting and CSS path work.
Heartbeat monitor flips down
Section titled “Heartbeat monitor flips down”The heartbeat must arrive within interval × tolerance. If your job is supposed to run every hour but takes 75 minutes, set tolerance accordingly. Pulse doesn’t know the difference between “job late” and “job dead” — that’s what tolerance is for.
I lost my Pulse admin password
Section titled “I lost my Pulse admin password”docker compose exec postgres psql -U pulse -d pulse \ -c "UPDATE users SET password_hash = NULL WHERE email = 'you@example.com'"…then /forgot flow against your own email to set a new one. If SMTP isn’t configured, the reset link appears in the API log (event=mail.dev_log).