Skip to content

OD322 unknown-selection-value

A data record gives a Selection field a value it does not list.

Category Severity Series Needs the index
Correctness Error all yes

What it reports

The text of a <field>, a whole string eval, or a CSV cell, written to a Selection field, when no definition of that field in any indexed module lists the value in a literal selection or selection_add. A field of an _inherits parent counts as a field of the child, unless the child has its own.

The value is compared as written, spaces included, because Odoo does not trim it either. A CSV cell also passes as a label, since the import looks both up, and from saas~14.3 as a value or label in another case. In an unknown series, any case passes.

Why it matters

Odoo validates the value on write, so an XML file raises ValueError: Wrong value for ..., and the import refuses a CSV cell with Value '%s' not found in selection field. Either stops the install or the update of the module. A demo file differs: see load failures. The usual causes are a value renamed in Python and missed in the data, a typo, and a label written where the value belongs.

The union over every indexed module is deliberate. A value another module adds with selection_add loads first when that module is auto-installed, so only a value no module lists is certain to fail.

The rule stays silent where only a run tells the values:

  • A selection given by a method, a lambda or a variable, or with int keys.
  • A tuple as selection from saas~17.2 up to saas~19.2, and in an unknown series. Odoo does not validate it on write there, except from saas~18.1 on a field with several definitions or one from another model, which the rule does not report either. A CSV cell still reports, since the import checks a tuple in every series.
  • A field with validate=False, a related field, a field that is not stored, and a field that unpacks **kwargs. A company-dependent field counts as stored, since Odoo validates its value like a column's, unless it declares store=False, or a compute without store=True.
  • A selection_add whose base no indexed definition lists.
  • A search, a ref, a type, a file, a name@lang field, and a bigger eval. Only the last <field> of a name counts.
  • An empty <field>, eval="''" and an empty CSV cell. Below saas~19.3 each clears the field, unless the selection lists ''. From saas~19.3 only the CSV cell and eval="False" do: the other two write '', so Odoo raises Wrong value for ... on a literal selection that lacks it, and stores it on a selection a method gives. The rule does not report that refusal.
  • The inverse field of a record nested in a one2many, and a record nested in any other type of field.
  • A value a later write replaces in the module's scope. A value only a module outside the scope replaces still reports, since a database without that module keeps it, and so does a data value only a demo write replaces, since a database may hold no demo data.
  • A file the manifest does not load.
  • A module with a dependency that is not indexed, a module that builds model names at runtime, and a model with a parent the scan cannot see.
  • A module with an unread data file, which may replace the value. A module that depends on one still reports, as that file has loaded by then.

Example

models/res_partner.py
class ResPartner(models.Model):
    _inherit = "res.partner"

    tier = fields.Selection([("gold", "Gold"), ("silver", "Silver")])
data/res_partner.xml
<odoo>
    <record id="partner_shop" model="res.partner">
        <field name="name">Shop</field>
        <field name="tier">Gold</field>
    </record>
</odoo>

Gold is the label, and tier stores gold.

data/res_partner.xml
<odoo>
    <record id="partner_shop" model="res.partner">
        <field name="name">Shop</field>
        <field name="tier">gold</field>
    </record>
</odoo>

The value is one the field lists.

Suppressing

<!-- odooscan: ignore[OD322] -->

See suppressing a finding.