Fixing Silent SMS Delivery Failures in the Notification Queue
Fixing Silent SMS Delivery Failures in the Notification Queue
Release: v1.0.25 · File:
src/inngest/functions/notification-queue.ts
Background
The platform's notification queue supports multiple delivery channels — including email and SMS — routed through the notificationSend Inngest function. SMS delivery is handled by calling sendSms(), which internally uses Twilio to dispatch messages to a recipient's phone number.
The Bug
A stub left over from development meant that, for any notification whose delivery channel included sms, the code was passing recipient.email as the To argument to sendSms() rather than the recipient's actual phone number.
// BEFORE (buggy — line ~180)
if (channel === 'sms') {
// phone number would come from employee record in production
await sendSms({ to: recipient.email, body: message });
}
Twilio validates phone numbers in E.164 format. An email address trivially fails this check, so every SMS Twilio received was rejected. Critically, the rejection was silent — no exception was re-thrown and no failed delivery was logged — so operators had no visibility into the problem.
Impact
- All SMS notifications failed for any notification type that included
smsas a delivery channel. - Failures produced no log entries, making the issue invisible in dashboards and alerting pipelines.
- Affected all tenants; severity was proportional to how heavily each tenant relied on SMS-based notification workflows (e.g. shift reminders, payroll alerts, contract approval nudges).
The Fix
The notificationSend function was updated to perform a proper employee record lookup before attempting SMS delivery:
- Look up the employee record linked to the notification recipient via
employees.userId. - Read the phone number from the employee record.
- Call
sendSms()with the resolved phone number if one exists. - Record a
faileddelivery log entry if no phone number is on file, instead of silently no-oping or throwing an unhandled error.
// AFTER (fixed)
if (channel === 'sms') {
const employee = await db.query.employees.findFirst({
where: eq(employees.userId, recipient.userId),
});
if (!employee?.phone) {
await logDelivery({ notificationId, channel: 'sms', status: 'failed', reason: 'no_phone_on_file' });
return;
}
await sendSms({ to: employee.phone, body: message });
}
Ensuring Employees Have Phone Numbers on File
With this fix in place, SMS delivery now depends on the employee record containing a valid phone number. To avoid failed delivery log entries:
- Prompt employees to add a phone number during onboarding or profile completion.
- Use the HR module's bulk employee import to include phone numbers from your existing directory.
- Review delivery logs for
reason: 'no_phone_on_file'to identify accounts that need updating.
Delivery Log Reference
Failed SMS deliveries are recorded with the following shape:
| Field | Value |
|---|---|
channel | sms |
status | failed |
reason | no_phone_on_file |
These entries appear in the Notification Delivery Logs section of the admin console and are queryable via the audit log API.