go-notificationgo-notification

Troubleshooting

Common problems and their fixes.

Symptom-first list of things that commonly break and what to check.

Nothing happens when I call Send()

  • In async mode, Send() returns immediately. Errors surface via OnError. Make sure you registered a handler.
  • Program exits before sends complete — add notifier.Close() before exit, especially in short-lived programs. It drains the worker pool and returns no error.
  • Channel not registered — if your Via() returns "mail" but you never registered a driver whose Name() is "mail" via RegisterChannel(...), you'll see an error in OnError saying "channel not registered".

OnError reports "channel not registered"

Exact name mismatch. The name returned by the registered driver's Name() must match the string returned by Via(). Case-sensitive.

Emails silently not delivered (but no errors)

This is almost always SMTP port blocking — see SMTP Port Blocking on Cloud. Switch to an API-based driver.

Otherwise, check:

  • The From address is verified with your email provider.
  • SPF, DKIM, DMARC are set on your sending domain.
  • The recipient isn't on a suppression list at the provider.

WhatsApp sends succeed but messages don't arrive

  • Unofficial APIs (WAHA / Fonnte / Wablas): session may have disconnected. Re-scan the QR or check the session health endpoint.
  • Official APIs (Twilio / Meta Cloud): you may be outside the 24-hour conversation window. Use an approved template.
  • Recipient has blocked your number — nothing you can do; detect via delivery webhooks if the provider offers them.

429 Too Many Requests from a provider

Your send rate exceeds the provider's limit. Lower the rate via notifier.SetRateLimit(channel, rate, interval, burst). If it's an intermittent spike (e.g., digest fan-out), raise the burst argument to smooth it.

Database channel rows missing

  • Migrations not run — the table may not exist. Run migrate.Up(ctx, db, dialect, "notifications") at startup and check logs for migration errors.
  • Wrong dialect — e.g., using database.DialectPostgreSQL with a MySQL connection will generate invalid SQL.
  • Transaction rollback — if you Send() inside a transaction that then rolls back, the async dispatcher has already inserted (or will). Move Send() after commit.

Slack webhook returns 200 but no message appears

  • Webhook is for a different workspace than you think.
  • The channel was archived or renamed.
  • Payload is structurally valid but semantically empty (e.g., both text and attachments empty) — Slack silently drops these.

FCM returns UNREGISTERED or INVALID_ARGUMENT

The device token is dead. Remove it from your database. Typical causes:

  • User uninstalled the app.
  • User disabled notifications in OS settings.
  • Token rotated (FCM refreshed it and the client didn't send the new one to your backend).

SMS delivered but user never got it

Carrier-side drop. Happens most in:

  • US — carriers (T-Mobile, Verizon) aggressively filter alphanumeric senders. Register a 10DLC campaign.
  • India — DLT registration required for all SMS. Unregistered = silently dropped.
  • UK — alphanumeric senders get rewritten, sometimes into unreadable names.

Use a proper short code or register a carrier-approved sender ID if SMS is mission-critical.

Close() blocks for a long time

Workers didn't finish draining. Close() waits for in-flight sends to complete. Either:

  • Make sure the contexts passed to Send() have sensible deadlines so slow sends don't hang the drain.
  • Investigate which channel is slow (add per-channel duration logging via OnSuccess).
  • Reduce QueueSize to make backlogs smaller by pushing back on the caller earlier.

High memory usage

  • Queue too large — reduce QueueSize.
  • Attachment payloads in memory — mail attachments are currently held fully in memory until send. For large files, consider hosting elsewhere and sending a link.
  • Too many worker goroutinesWorkerPool defaults to 10. Tune it for your workload; sends are mostly I/O-bound, so a larger pool is usually fine, but a huge pool plus a large queue raises memory.

Build errors after upgrading

  • Zod-related error in Fumadocs builds — we pin Fumadocs to 15.5.5 and Zod to ^3 for this reason. Don't upgrade those packages without testing a build.
  • useEffectEvent not exported in Fumadocs v16 — requires React canary. Stick with Fumadocs 15.x for stable React.

Still stuck?