Skip to main content

Troubleshooting: IVR NLU intent catalogue authoring rejections

The intent catalogue is where you author the named intents and example utterances your conversational IVR classifies against. Writes to it — creating an intent, renaming one, deleting one — can be rejected with four codes that are entirely about your request, not about the model layer. This page decodes each code, the change that clears it, and how these authoring-time rejections differ from the runtime 503s the classifier throws on live calls.

Authoring rejections are not runtime 503s

Two different failure families share the NLU surface:
  • Authoring-time rejections (this page). Returned by the catalogue endpoints under /api/v1/voice/ivr-nlu-hints when a create, update, or delete cannot be applied: a full catalogue, a name already taken, a stale id. They are deterministic — the same request gets the same rejection until you change it — and the model layer is fine.
  • Runtime 503s — IVR_CLASSIFY_LLM_ERROR and IVR_SLOT_EXTRACT_LLM_ERROR — hit live calls when the classifier or slot-extractor leg goes down. The catalogue is fine; the model call is not. Recovery for those (re-prompt, DTMF fallback, queue) lives on IVR NLU classifier and slot-extraction failures.
If a 503 lands while you are authoring, or a catalogue code appears on a live call, you want the other page of the pair.

The catalogue write rejections

IVR_NLU_CATALOGUE_FULL — the 64-intent cap

A tenant catalogue holds at most 64 intents. The cap is checked before the insert, so a rejected create writes nothing partial. To free a slot, list the catalogue (GET /api/v1/voice/ivr-nlu-hints) and delete an intent your flows no longer reference — deletion is the only way to release a slot, so prefer deleting intents that are truly retired over ones you might tune later. If you are close to the cap because many intents cover one menu, consider merging intents whose descriptions phrase the same middle ground; the routing guide covers description craft.

IVR_NLU_NAME_CONFLICT — names are unique per tenant

Intent names are lowercase alphanumeric with hyphens or underscores, max 64 characters, unique per tenant — the same handle rules the routing guide teaches. Re-posting a create with a name that already exists returns this 409, which commonly bites scripts that retry a create after a network error: the first attempt may have succeeded. List the catalogue, find the existing intent, and PATCH its description or utterances instead of posting the create again. A PATCH that keeps an intent’s own name never conflicts; only renaming onto another intent’s name does.

IVR_NLU_CREATE_ERROR — retry once, then escalate

A 500 on create means the write failed for a non-conflict reason — transient by design of the code, unlike the deterministic 422 and 409 above. Retry once with an identical body; a create writes nothing until it succeeds, so the retry cannot double-insert. If the second attempt also returns IVR_NLU_CREATE_ERROR, escalate with the request_id the error envelope carries.

IVR_NLU_NOT_FOUND — stale id on update or delete

Ids are stable for the life of an intent, but a delete removes them outright. A script or dashboard tab holding an id from an earlier session 404s once another writer deletes that intent. Re-list the catalogue before batching updates or deletes, and treat IVR_NLU_NOT_FOUND on a delete as already-done rather than an error.

Malformed payloads return VALIDATION_ERROR

A name with uppercase letters or spaces, an empty utterance, an utterance over 100 characters, or more than 16 utterances on one intent does not return a catalogue code — it comes back as the generic VALIDATION_ERROR 422 with a details map naming the offending field. Fix the field and resend; the catalogue codes above only return for well-formed requests the catalogue itself refuses.

See also