In these docs

Execution Layer for Odoo

Troubleshooting.

The common things that go wrong when connecting an AI client to the Execution Layer, and what each one means, from a 401 on the endpoint to an ambiguous target or a client in the cloud that cannot reach your Odoo.

Feature-complete · Odoo 19 Updated 17 August 2026

Most issues fall into a handful of shapes. The Execution Layer’s errors are structured, so the code usually tells you the fix.

A 401 with WWW-Authenticate

The request is not authenticated. Run the OAuth flow for your client (see connecting an AI client): the client should open the Odoo login and you sign in as yourself, then click Allow. For scripts, send a scoped API key as Authorization: Bearer nmk_....

TOOL_NOT_AVAILABLE or MODEL_FORBIDDEN

The tool or model is out of scope for this user. This is governance working as intended, not a bug. The refusal carries a fix_location pointing at the bundle or connection to adjust. Widen the bundle or the connection’s access level, then retry.

APPROVAL_REQUIRED

The action is risk-classed and was staged rather than run. A person, who can be someone other than the requester, approves it in Odoo’s activity inbox. Once approved, the agent retries the identical call with the approval_request_id. If the payload changed in between, the retry returns APPROVAL_STALE; re-stage it.

AMBIGUOUS_TARGET

A human reference matched more than one record. The refusal returns the candidate list. Resolve it by a unique field, an email or a code, or ask the person which record they meant, then call again. The layer will not guess.

A cloud client cannot connect

ChatGPT and the Claude web app run in the cloud, so they need your Odoo reachable over the public internet on HTTPS, with proxy_mode = True behind your reverse proxy. Local clients (Claude Code and Desktop, Cursor) do not: a LAN or VPN is enough. Check the reachability table.

IDEMPOTENCY_CONFLICT

The same idempotency key was reused with a different payload. Use a fresh key for a genuinely different write; reuse the same key only to safely retry the same one.

A read looks short

Check the read’s truncated and total_count. A bounded read reports exactly how much it left out, so page through with next_offset before treating the result as complete. This is the truncation contract, doing its job.

Multiple databases

If the host serves more than one database and a client lands on the wrong one, send X-Odoo-Database: <db>. The supported deployment is one database per host, which avoids this.

Still stuck? Everything the AI did is in the audit, and every refusal is recorded there with its code and detail.