Skip to main content

Troubleshooting: Messenger channel not connected

A Messenger channel write or persona operation returns 409 MESSENGER_NOT_CONNECTED when Meta is missing a valid connection for the channel the request targets. On the Messenger lane it fires on the persona calls — list, create, delete — whenever the stored connection is marked disconnected or it carries no Page access token at all. Refusing the call instead of sending it to Meta is intentional: persona operations would fail at Meta with a far less readable error if Orbit forwarded them without a token. The 409 is a connection-state refusal, not a permission or validation failure — no amount of request reshaping fixes it. Only reconnecting the Page flips the condition the guard reads.

When the 409 fires

The guard reads the connection row for the Messenger channel, and any caller that resolves the stored Page access token routes through it — so the list/create/delete surface is the whole persona surface. Read the sibling codes off the same refusal class — they route to different fixes:

Routing by the error envelope

The envelope carries the channel under a structured detail, so a blocked writer routes readers by the exact code:
For Messenger both “nothing stored” and “stored but disconnected” collapse into MESSENGER_NOT_CONNECTED, and the fix is identical either way — so this particular code needs no channel branch. Sibling channels DO split it — LINE’s LINE_NOT_CONFIGURED is a settings-completeness refusal, where a raw token/email config is absent, and other channels branch NOT_CONNECTED from CONNECTION_INVALID. Routing code should read details.channel_id before lumping every refusal onto “reconnect.”

Diagnose: confirm the channel is really disconnected

Check either surface before touching OAuth — some disconnected reports turn out to be MESSENGER_TOKEN_UNREADABLE, which needs the same reconnect but starts from a different envelope, so confirm the code you actually got.
  1. Dashboard surface. Open Settings → Channels → Messenger. The status badge reports disconnected (no connected mark) or expired (token present but past its rotation window) — either routes into the reconnect flow below.
  2. API surface. Read the channel-status surface:
    For the Meta-adjacent channels the richer connected/token view (valid / expiring_soon / expired) rides on this endpoint. A disconnected channel reports the connection as absent; a MESSENGER_TOKEN_UNREADABLE-class channel still reports a token but the endpoint cannot vouch for its decryptability.

Fix: flip the channel back to connected

Two self-serve reconnect paths replace the stored token with a fresh, correctly scoped one. Pick OAuth (recommended) or the scope-repair flow when your company’s Meta app-review approves fewer scopes than the Page picker requests.

Path A — OAuth reconnect with the Page picker

The full ordering is on the Messenger channel page; condensed for this recovery:
  1. In Settings → Channels → Messenger, click Reconnect.
  2. Meta’s OAuth dialog re-opens; re-select the Page you were using (the dialog lists Pages you administer).
  3. Outbound sends and persona operations resume as soon as the stored token is replaced.

Path B — re-attach the required Meta scopes

If the OAuth dialog completes but the channel still refuses with the 409, the scopes granted to the Meta app were narrowed. Re-run the dialog with both scopes checked (per the channel page’s required-scopes list): Re-running the dialog with both scopes re-selected flips the stored row back and the 409 stops.

Confirm the flip

The condition the guard checks is the connection row having connected plus a stored Page access token. After either path, re-read the channel status — a healthy reconnect reports the channel as connected with the token valid (or expiring_soon; that still satisfies the guard — the 409 fires only on absent). Then retry the refused personas call once. Do not loop it against the 409: the refusal is deterministic, and a loop re-reads the same guard on every attempt.

Distinguish from the not-configured family

Sibling channels split “nothing has ever been set up” into a *_NOT_CONFIGURED code (412) instead of *_NOT_CONNECTED (409). The distinction is bookkeeping, not severity, and it matters only to routing code: the NOT_CONFIGURED family means the tenant’s settings payload never carried that channel at all (self-serve: store the credential), while NOT_CONNECTED means a channel row exists but the connection guard reads it as disconnected (self-serve: reconnect). Route on details.channel_id before picking a remediation, and never treat a NOT_CONFIGURED as a reason to re-OAuth something that was never set up.

When NOT to retry

  • Do not retry the same personas request. Every retry hits the same guard and returns the same 409 until a reconnect lands.
  • Do not retry with a different persona name or avatar. The refusal fires before any persona data is read; nothing in your request body can steer around it.
  • Do not create new personas while disconnected. The guard refuses list/create/delete identically; the read side also 409s.

Escalation checklist

Open a ticket when the channel status reports connected, the OAuth dialog completed with both scopes, and the personas call still 409s. Include:
  • The request_id from meta on the 409.
  • The exact endpoint you were calling (list, create, or delete).
  • The channel status snapshot (dashboard badge or the API read).
  • The code you received — MESSENGER_NOT_CONNECTED vs MESSENGER_TOKEN_UNREADABLE splits the follow-up.

See also