Skip to content

json2s: Cloudflare-fronted Odoo blocks model introspection (GET /doc-bearer), breaking positional-arg RPC #213

Description

@bosd

Summary

Importing/operating against a Cloudflare-fronted Odoo behind the json2s (bearer) protocol breaks because odoolib's json2 client introspects each model via GET /doc-bearer/<model>.json, and Cloudflare returns a JS challenge (HTTP 403 "Just a moment…") for that GET. Any call made with positional arguments triggers introspection and fails before reaching Odoo.

Hit during a real migration against a client test env (multi-company, Cloudflare in front, protocol = json2s).

Reproduction

conn = conf_lib.get_connection_from_config(json2s_conf)
conn.get_model('ir.model').search_read([('model', 'like', 'x')], ['model'])  # positional args
# -> odoolib json2 does GET /doc-bearer/ir.model.json -> Cloudflare 403 -> call never reaches Odoo

Root cause

odoolib/json2.py _introspect() does GET {base}/doc-bearer/{model}.json to map positional args → param names. The /doc-bearer/ GET path is challenged by Cloudflare, while the actual RPC POST /json/2/<model>/<method> is not (it reaches Odoo fine).

Workaround (confirmed working)

Call with keyword arguments only — that path skips _introspect() and POSTs straight to /json/2/:

conn.get_model('ir.model').search_read(domain=[('model', 'like', 'x')], fields=['model'])  # kwargs -> works

The whole migration import then works over json2s (locations, products, supplierinfo via the importer; data reads via kwargs).

Suggestions

  • Make introspection optional / skippable (e.g. a connection flag), or
  • Fetch the method schema over the same POST channel instead of the /doc-bearer/ GET, or
  • At minimum, document that json2s against Cloudflare-fronted Odoo requires kwargs-only calls, and have the importer prefer kwargs.

Related migration gotchas worth capturing (same env)

  • Multi-company import: new stock.location / product.template / product.supplierinfo must carry company_id to satisfy the cross-company parent constraint; but inventory-mode stock.quant create rejects company_id (only an allow-listed field set is permitted) — company must come from the location + allowed_company_ids context instead.
  • Supplier xmlid: product.supplierinfo.partner_id/id must use the partner's actual export xmlid (__import__.<contact-id>), not __import__.<ref>.
  • Per-call context does forward over jsonrpc; needed for inventory_mode inventory adjustments.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions