Skip to main content

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 to retry — 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.
An identical 422 also comes back from the pool preview endpoint (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.

Causes

The pool row exists and resolves — the failure is membership:
  • The pool’s sender_dids list 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.

Fix: put a sender in the pool

Either fix the pool itself, or route the send elsewhere — tenant-owned controls only.
  1. Add at least one member to the pool. A pool member can be an E.164 DID, a numeric short code, or an alphanumeric sender ID — update the pool with PATCH /api/v1/messaging/sender-pools/{id} and set sender_dids, or add the sender in the dashboard’s pool editor. Make sure the sender is one your organisation actually owns: GET /api/v1/numbers lists the DIDs on your organisation before you send.
  2. Route through a pool that has members. Pass a different sender_pool_id on the request, or repoint the wiring that led here — a messaging service’s default pool, a campaign, or a routing rule — at a non-empty pool.
  3. Retry the send. SENDER_POOL_EMPTY is rejected before any pick is made, so no selection state was written for the recipient — the retry routes cleanly, and the same idempotency key resubmits without a duplicate.

Distinguish it from the neighbouring codes

The telling difference: SENDER_POOL_EMPTY is pool-level state (a good pointer, an empty list), SENDER_POOL_NOT_FOUND is the pointer itself (there is no pool), and NO_SENDER_CONFIGURED is organisation-level state (no sender of any kind yet).

Example envelope

returns HTTP 422: