ODXProxy

Error Codes

The ODXProxy JSON-RPC error catalog for v1 and v2, the two-step success check, and what is safe to retry.

Every /api/*, /v1/*, and /v2/* response is a JSON-RPC 2.0 envelope. result and error are mutually exclusive:

{
  "jsonrpc": "2.0",
  "id": "<echoed request id>",
  "result": "<any> | omitted",
  "error": { "code": 0, "message": "...", "data": "<any> | omitted" }
}

Codes 0 and below are the proxy's. Codes from 100 to 599 are Odoo's HTTP statuses, passed through on v2. You can rely on that split.

Catalog

HTTPJSON-RPC codeAPIWhen
200Odoo's own codev1Odoo logic error (pass-through; data carries Odoo's payload). Odoo 19+ uses code 0 here; older versions use 200.
200401v2Odoo rejected its API key: invalid, expired, wrong scope, or a password.
200403v2Access rights, or a private (_-prefixed) method.
200404v2Unknown model or method, or the record doesn't exist.
200409v2Odoo lock conflict.
200422v2Validation or user error, or bad arguments (an unknown kwarg, ids on an @api.model method).
200500v2Odoo server error.
200-32006v2JSON-2 isn't available: Odoo 18 or older (use v1), or the database isn't selectable on that host (dbfilter).
400-32001v1action not in the allowlist.
400-32002v1call_method without fn_name.
400-32007v2model_id or method isn't a valid Odoo identifier, or db / api_key can't go in an HTTP header. Odoo isn't contacted.
401-32000bothMissing/wrong x-api-key (id is null).
4030bothProxy license expired/invalid.
502-32004bothNetwork failure reaching Odoo.
504-32003bothUpstream Odoo call timed out.
500-32005bothInternal proxy error decoding Odoo's response.

A request body that doesn't match the schema at all (for example, v2 kwargs that isn't a JSON object) gets HTTP 422 with a plain-text message, not an envelope.

Do not infer success from the HTTP status alone

A 200 OK response can still contain an error object — Odoo logic errors (validation, access-right denial) are returned this way. Clients must:

  1. If the HTTP status is not 200, treat it as a proxy-level failure and surface the JSON-RPC error.
  2. If the status is 200, check whether error is set. If so, surface it; otherwise read result.

Codes that look alike

  • Two kinds of 401. HTTP 401 with -32000 means the proxy key (x-api-key) is wrong — a deployment problem. HTTP 200 with code 401 means Odoo rejected the Odoo user's key — usually because a non-admin key expired, so the end user needs to issue a new one. Handle them separately.
  • Code 0 is a license error only on HTTP 403. Odoo 19+ also uses code 0 for every v1 Odoo error, on HTTP 200. Classify by HTTP status first.
  • Read data, not message, on v1 Odoo errors. v1's top-level message is just Odoo Server Error. On both versions error.data is Odoo's error object { name, message, arguments, context, debug }: data.message is the readable text and data.name the exception class (e.g. odoo.exceptions.ValidationError) to branch on. Never parse data.debug — it's a traceback and may be empty.

What to retry

CodeRetry?
-32004 (proxy couldn't reach Odoo)Yes, with backoff.
409 (Odoo lock conflict)Yes, with backoff.
-32003 (timeout)Only for idempotent calls such as reads. The proxy stopped waiting, but Odoo may still have run the call — retrying a create can duplicate it.
Everything elseNo. Fix the request, the configuration, or the data first.

The official SDKs map these codes to typed errors and never retry on their own.

On this page