Dil notu
Çeviri mevcut değilse İngilizce içerik yedek olarak gösterilir. Hata kodlarını, API yollarını ve kod bloklarını değiştirmeyin.Fix an empty sender pool (SENDER_POOL_EMPTY)
SENDER_POOL_EMPTY is a deterministic, pre-send rejection: your request
named a valid pool, Orbit looked up the pool, and found it has no members
to draw a sender from. The send never reaches a provider, so nothing
needs a carrier-side reconciliation — add a member to the pool (or route
through a different pool) and send again.
Symptoms
- The send request returns HTTP 422 with code
SENDER_POOL_EMPTY, and the response names the pool that was empty. - The dashboard Delivery Log shows no row for the message — the send was rejected before queueing, so there is nothing to deliver.
- The pool’s detail page prompts you to add a DID, and the senders list for the pool is empty.
GET /api/v1/messaging/sender-pools/{id}/preview) when the pool has no
members, so the symptom surfaces before you send real traffic if you
preview first.
The sender-pool state machine
An empty pool sits between two healthier states, and a third failure state shares its 422 status. Tracking which state you are in tells you whether a fix has landed:
The pool preview endpoint exercises that resolution step read-only, so
you can walk the state machine without sending traffic — the empty →
resolved transition shows up there the moment a member lands.
The neighbouring codes split the failed-to-resolve state by where the
break sits, and each one has its own clear action:
SENDER_POOL_EMPTY is pool-level state (a good pointer, an empty list),
SENDER_POOL_NOT_FOUND is the pointer itself, and
NO_SENDER_CONFIGURED is organisation-level state.
Causes
The pool row exists and resolves — the failure is membership:- The pool’s
sender_didslist has no entries. Two ways a pool reaches that state: it never had members (created with an empty list and never filled, or the last member was removed), or the send carried a narrower recipient filter and none of the pool’s members were eligible, leaving zero candidates for that recipient. - A messaging service, campaign, or sender routing rule still points at the pool, so every send routed through it fails with the same code.
Pool membership mechanics
A pool member can be an E.164 DID, a numeric short code, or an alphanumeric sender ID — owned by your organisation:- E.164 DID — listed by
GET /api/v1/numbers; check the inventory before attributing the empty-pool rejection to a missing row. - Numeric short code or alphanumeric sender ID — set via the API
(
PATCH /api/v1/messaging/sender-pools/{id}withsender_dids); the dashboard’s pool editor carries them over when you edit there.
The in-flight retry semantics
SENDER_POOL_EMPTY is rejected before any pick is made, so no selection
state was written for the recipient — a retries-after-fix sequence moves
from correct-by-construction to explicitly defined:
- The idempotency key survives the pool swap. The key scopes to the request, not to the pool id inside it — when you fix membership (or route through another pool) and resubmit the same key with the same body, Orbit returns the cached 422 instead of a second send.
- The body must be byte-identical. If your fix changes the body —
for example a different
sender_pool_idvalue — the same key resubmits to409 IDEMPOTENCY_KEY_REUSED, not to a send. Generate a fresh key for the corrected request, or leave the key unset (neither the 422 nor the 409 consumes the rejection). - Nothing wrote a cache entry to clean up. Because the rejection happens before queueing, the idempotency cache holds either nothing (the plain rejection) or the 422/409 itself — both expire on the key’s 24-hour window. There is no mid-batch selection state to unwind; the idempotency and safe retries concept page covers the key-vs-body binding in full.
Gate it before launch: preview as a diagnostic
The preview endpoint rejects withSENDER_POOL_EMPTY the same way a
send does, and stays read-only — it never advances a round-robin
counter or writes a sticky assignment, so it costs nothing to run as a
pre-launch gate.
- Run
GET /api/v1/messaging/sender-pools/{id}/preview?recipient=<E.164>on a synthetic recipient after provisioning or editing a pool; expect a sender, not the 422, before you wire the pool into a campaign or messaging service. - Combine with
GET /api/v1/numbersso the pre-launch check both resolves and owns its sender before traffic flows. - When a recipient filter narrows the pool to zero candidates, preview the actual recipient you will send to — the failure mode is narrower than the empty list the pool row itself reports.
Route elsewhere: pass a sender_pool_id, or repoint the wiring
When the right move is to sidestep the empty pool rather than fix it:
- One-off divergence — pass a different
sender_pool_idon the send request itself (generate a fresh idempotency key, per the retry semantics above). Use this when only certain traffic should route away. - Wiring repoint — move the messaging service’s default pool, the campaign, or the routing rule to a non-empty pool when everything routed through the empty pool should move. Use this when the pool itself is being retired or reworked.
Client hints: branch on the confirmed channel and sender
Once a sender is in the pool, the fuller client-hint model covered on the Instagram channel page applies here too: pick the outbound sender onmetadata.channel and the source
message.from of the inbound event that started the thread, rather
than hardcoding a pool member. For a pool-backed thread the inbound
event narrows the candidates to a remembered or geo-matched pick.
Composite recovery
Example envelope
Related references
- Sender pools — create pools, add members, and understand selection strategies.
- Sender resolution — where the pool pick sits in the full precedence chain.
- Idempotency and safe retries — the key-vs-body binding semantics the retry section above applies.
- Troubleshoot sender resolution and pool errors
— the three sibling codes (
SENDER_REQUIRED,SENDER_POOL_NOT_FOUND,NO_SENDER_CONFIGURED). - FAQ: Why did my send return
422 SENDER_POOL_EMPTY? — the one-line version of this page. - Error codes — the full sender error table.