Skip to main content

Troubleshooting: template fallback variant missing

A POST /messages/content-templates create failed with HTTP 400 and the error message:
That means the template you tried to author declares channels in its fallback_chain that have no variant in its variants map. The named fallback variant is missing — the chain entry promises a substitute that was never authored. Orbit refuses to save the template rather than let a declared-but-unrendered fallback channel surface later, at send time, as an unexpected resolve failure.

Why the guard fires at authoring time

A fallback chain is a promise: “when the target channel has no variant, try these channels in order.” A chain entry for a channel nobody authored a variant for cannot honour that promise. If the create succeeded, the orphan entry would sit in the chain until a render or send walked to it, skipped it (a chain hop with no variant resolves nothing), and either jumped to a later hop or failed the request with the 422 NO_VARIANT_FOR_CHANNEL error — depending on whether anything after it resolved. The create-time check turns that latent failure into an immediate, explicit one. The error message lists every orphaned channel, so the payload you sent and the fix are in the same round trip.

Find the orphaned entries

Compare the two parts of your own payload:
  1. variants is a map keyed by channel name — its keys are the only channels the template actually covers.
  2. fallback_chain is an ordered list of channel names — every entry must appear as a key in variants.
Any chain entry that is not a variants key is named in the error message after channels with no variant:. The check compares the payload you sent, not the stored template — on a create, fix the payload before you retry. The same gap can also appear on a template that was created before this guard existed, or introduced by a later partial update that replaced variants or fallback_chain separately. Fetch the template (GET /messages/content-templates/:id) and diff variants keys against fallback_chain — every chain entry must have a variant.

Fix it one of two ways

Pick the fix that matches your intent:
  • Author the missing variant. The fallback entry was deliberate — you want the substitute. Add the variant for the named channel to the variants map, with the channel-rendered copy it needs (components for WhatsApp, subject + body_html for email, body for SMS), then re-send the create or run PATCH /messages/content-templates/:id.
  • Remove the orphaned entry from the chain. The entry was a mistake — nobody plans to author that channel. Drop it from fallback_chain and keep the chain entries that do have variants. The chain walks in order, so check the surviving entries still give you the substitute order you want.
Either fix must hold for every chain entry — the guard rejects the request if even one entry is orphaned.

Confirm the fix with a render

Once the template saves, prove the chain actually resolves by rendering against a channel the template does not cover:
  1. Run POST /messages/content-templates/:id/render with target_channel set to a channel absent from variants.
  2. The response’s rendered_channel should be the first fallback-chain entry that has a variant, and resolution should be "fallback".
  3. If the response is instead a 422 NO_VARIANT_FOR_CHANNEL, the chain still does not resolve — see template variant missing for the resolve-time side of this error family.

Where this usually goes wrong

  • Chain updated, variants not. A partial update replaced the chain with one that names a channel whose variant was never written. Diff the two maps whenever either changes.
  • Variant removed, chain left behind. Deleting a variant (rewriting variants without a channel) while its name stays in fallback_chain recreates the orphan on an older template.
  • default_channel in the same boat. Create also rejects a default_channel that has no variant in the payload. The fix is the same: author the variant or point the default at a covered channel.

See also