Troubleshooting: message stuck in queued
A message that stays atqueued has not been sent to a provider yet — it is
sitting in the pre-delivery stage. This page walks you through what each
status means, the causes that park a message at queued, and how to unstick
it without making the problem worse.
Distinguish two failure shapes before you start: a row at queued has
never left Orbit — the hold is on your side of the provider handoff, and
this page is the diagnostic. A row at submitted_no_receipt has already
left Orbit and is waiting on a carrier delivery receipt — that is the
post-queue stage, covered by the
message sent but no delivery receipt
page.
How message statuses fit together
Every message moves through a defined set of statuses, and each transition is gated — a message cannot jump fromqueued straight to delivered, and a
terminal status like read or failed cannot move backward. The happy path
for an immediate send is:
scheduled until its send_at
time arrives, then joins the queue:
accepted (the synchronous pre-queue handoff), test_sent
(sandbox mode), and cancelled (a scheduled message you cancelled before it
sent) exist alongside the main path. Status updates are ordered, so each row
can only move forward along an allowed transition — a stale carrier callback
cannot drag a settled message back to queued.
Where to check the status
- Delivery Log: open Messages → Tools → Delivery log and search the
message ID (
msg_…), the provider reference, or the recipient. Filter by the Status filter to isolate stuck rows — for example/messages/delivery-log?status=queued&direction=outboundshows every queued outbound message. See the Delivery Log guide. - Per-channel workspace: SMS, WhatsApp, and Email channels each show outbound history with the same status values.
- API: call
GET /api/v1/messageswith astatus=queuedfilter, or fetch the row by ID. Thestatusfield tells you where the row is; the response also tells you whether the row carries asend_at(scheduled), or a provider reference once it reachessent.
Common causes and how to unstick them
Work through these in order — they cover the overwhelming majority of queued-for-longer-than-expected rows.A message that never gets a delivery receipt moves to
submitted_no_receipt — that means it left the queue. A row still at
queued has never left the queue, which is exactly the state this page
diagnoses.Diagnosis checklist
- Get the message ID. Open the Delivery Log or your channel workspace
and copy the
msg_…ID from the row. - Read the message detail. Open the full message detail page — it shows the send channel, the sender pool, the scheduled time if one exists, and the campaign it belongs to. Each of those fields maps to a row in the cause table above.
- Check the campaign. If the message came from a campaign, open that campaign’s settings: frequency caps, quiet hours, and sender pool are configured there.
- Check tenant-level compliance settings. Quiet-hours and sender-registration gates are organization-wide. Confirm the hold is intentional before you clear it.
- Query the API if the dashboard shows conflicting data.
GET /api/v1/messages/:idreturns the authoritativestatus,send_at,channel, and any provider reference.
What not to do
Do not spamPOST /api/v1/messages/:id/retry while the cause is unknown. A
retry against a quiet-hours hold, a pending sender approval, or a capped growth
window just moves the same blocked message through the same gate again. Fix the
cause first, then retry.
Also avoid re-sending a fresh copy of the message to an end user while the
original row is still queued — once the hold clears, both copies go out, and
your recipient receives the same content twice.
When to escalate
If you worked through the checklist, the cause is not a hold you control, and messages are still stuck for more than a few minutes, open a support ticket and include both of these so we can trace the row without a back-and-forth:- Your tenant ID (shown in the dashboard under Settings → Organization,
and returned by the
GET /api/v1/meresponse asorganizationId). - The message ID of one stuck row (
msg_…).
currentDay and todayCap values from GET /api/v1/email/warmup-status —
so support can tell a deliberate ramp hold from a real fault on the first
reply.
That pair lets support pull the exact queue entry and the exact send-gate
evaluation without you having to re-describe the symptom.
Status decoder
Every status value the Delivery Log filter and theGET /api/v1/messages
response can return, and what it means for diagnosis:
If a row is sitting on any of the blocked-in-queue statuses (
queued,
scheduled, pending, accepted, sending) for longer than you expect,
the cause table and checklist above will get you to the hold faster than a
blind retry.