DEV Community

Aaron Jones
Aaron Jones

Posted on

QWeb/View Inheritance Collisions

Problem Statement: UI breaks or customizations disappear when multiple modules try to extend the same XML view without proper priority or XPath, causing view conflicts or missing UI elements.

Step 1 Confirm the exact view that is colliding
In Odoo UI (Developer Mode)

  1. Turn on Developer Mode
  2. Go to the broken page (form/tree/kanban)
  3. Click the bug icon
  4. Select “Edit View: Form” (or Tree/Kanban)
  5. Note: o Original View External ID o Inherited Views list (you will often see multiple modules inheriting it) This tells you which view(s) are stacking and causing collisions.

Step 2 Open the view and find the failing XPath
Most collisions happen because your XPath is too generic or the structure changed by another module.
Common error logs:
Element '<xpath expr="...">' cannot be located in parent view
View validation error
• UI missing fields/buttons/groups after module install
To see the exact error:
./odoo-bin -d your_db -u your_module --log-level=debug

Step 3 Fix XPath by making it more specific (most important solution)
Bad (too generic, breaks easily)

<xpath expr="//group" position="inside">
    <field name="x_custom_field"/>
</xpath>
Enter fullscreen mode Exit fullscreen mode

If another module rearranges groups, your XPath can hit the wrong place or not match at all.

Good (target exact location)
Example: insert after a specific field:

<xpath expr="//field[@name='partner_id']" position="after">
    <field name="x_custom_field"/>
</xpath>
Enter fullscreen mode Exit fullscreen mode

Or target a specific page/tab:

<xpath expr="//page[@name='order_lines']" position="inside">
    <group>
        <field name="x_custom_field"/>
    </group>
</xpath>
Enter fullscreen mode Exit fullscreen mode

More stable because it anchors on a known element.

Step 4 Use priority to control view order
If multiple inherited views are modifying the same node (same button/group/page), order matters.
Add a priority on your inherited view record

<record id="sale_order_form_inherit_custom" model="ir.ui.view">
    <field name="name">sale.order.form.inherit.custom</field>
    <field name="model">sale.order</field>
    <field name="inherit_id" ref="sale.view_order_form"/>
    <field name="priority" eval="90"/>  <!-- higher loads later -->
    <field name="arch" type="xml">
        <xpath expr="//field[@name='partner_id']" position="after">
            <field name="x_custom_field"/>
        </xpath>
    </field>
</record>
Enter fullscreen mode Exit fullscreen mode

Rule:
• Higher priority → applied later → can override earlier changes.
If another module has priority 99 and yours is 16, their changes may override yours.

Step 5 Avoid replacing large blocks (use add/attributes instead)
Replacing full sections causes collisions.
Dangerous (replaces whole page)

<xpath expr="//page[@name='other_info']" position="replace">
    <page name="other_info" string="Other Info">
        ...
    </page>
</xpath>
Enter fullscreen mode Exit fullscreen mode

If another module modifies that page, it may get wiped out.

Safer: use position="attributes" or insert smaller changes
Example: just hide/show something:

<xpath expr="//field[@name='client_order_ref']" position="attributes">
    <attribute name="invisible">1</attribute>
</xpath>
Enter fullscreen mode Exit fullscreen mode

Example: insert only your field:

<xpath expr="//group[@name='sale_group']" position="inside">
    <field name="x_delivery_notes"/>
</xpath>
Enter fullscreen mode Exit fullscreen mode

Step 6 If the other module changes structure, inherit their inherited view instead
Sometimes you inherit the base view (sale.view_order_form)but the UI you see is already modified by another module.
In that case, inherit the view that actually creates the final structure.
Example:
Module A inherits sale.view_order_form and changes layout.
Your module should inherit Module A’s view instead (if it’s guaranteed installed).

<field name="inherit_id" ref="module_a.sale_order_form_inherit_a"/>
Enter fullscreen mode Exit fullscreen mode

And in manifest:

'depends': ['sale', 'module_a'],
Enter fullscreen mode Exit fullscreen mode

This makes your XPath match the structure you're actually extending.

** Step 7 Debug the final compiled view (best troubleshooting)**
In developer mode:

  1. Open the form
  2. → Edit View
  3. Click “View” then: o check Inherited Views o click “Manage Views”
  4. Use “Preview / View Architecture” to see the final compiled XML If your field exists in your view but not in compiled architecture → it is being overridden/removed by another inherit.

Step 8 Example: Two modules collide on same button
Module A adds a button:

<xpath expr="//header" position="inside">
    <button name="action_confirm" type="object" string="Confirm"/>
</xpath>
Enter fullscreen mode Exit fullscreen mode

Module B tries to hide it but XPath doesn’t match:

<xpath expr="//button[@name='action_confirm']" position="attributes">
    <attribute name="invisible">1</attribute>
</xpath>
Enter fullscreen mode Exit fullscreen mode

If Module A uses a different name or duplicates button, B may fail.
Fix by anchoring using string + name + parent:

<xpath expr="//header/button[@name='action_confirm' and @type='object']" position="attributes">
    <attribute name="invisible">1</attribute>
</xpath>
Enter fullscreen mode Exit fullscreen mode

Step 9 Clean upgrade and clear cache
After changes:
./odoo-bin -d your_db -u your_module --dev=xml --log-level=debug
Also hard refresh browser (Ctrl+Shift+R) if JS assets changed.

Conclusion
QWeb/view inheritance collisions happen because multiple modules modify the same view, and Odoo applies them in a specific order. If your XPath is too generic, targets an element that another module moved, or your view loads earlier than competing views, your UI customizations can disappear or break.
To fix it reliably:
• Use precise XPath anchored to stable elements
• Set proper priority so your changes apply at the correct stage
• Prefer small inserts/attributes instead of replacing large blocks
• Inherit the “real structure view” if another module heavily modifies the base view
• Always debug the compiled final view in Developer Mode

Top comments (0)