Skip to content

Fix Odoo Product Variant Errors: Attribute Conflicts, Missing Variants, and Duplicates

DeployMonkey Team · March 23, 2026 10 min read

The Product Variant Problem

Product variants in Odoo (e.g., a T-shirt in sizes S/M/L and colors Red/Blue) are powerful but error-prone. When variant generation fails, duplicates appear, or attributes conflict, it affects inventory, pricing, and sales. Understanding how Odoo generates variants is key to fixing these issues.

How Variant Generation Works

Odoo generates variants as the Cartesian product of all attribute values:

# Product Template: T-Shirt
# Attribute: Size (S, M, L) → 3 values
# Attribute: Color (Red, Blue) → 2 values
# Variants generated: 3 × 2 = 6 variants

# Each variant (product.product) has:
# - Unique combination of attribute values
# - Its own barcode, price extra, stock level
# - References the parent template (product.template)

Error 1: Variants Not Being Created

# Symptoms: Added attributes but no variants appear

# Cause 1: Attribute creation mode is wrong
# Product → Attributes & Variants tab → check "Variant Creation Mode":
# - "Instantly" — creates variants when values are added
# - "Dynamically" — creates variants when added to a sale/purchase order
# - "Never" — used for product configurator only, no actual variants

# Fix: Change to "Instantly" for physical products that need inventory tracking

# Cause 2: Attribute has only one value
# An attribute with only one value doesn't create multiple variants
# The product stays as a single variant

# Cause 3: Module not installed
# sale_product_configurator module may be needed for dynamic variants

Error 2: Duplicate Variants

# Symptoms: Same size/color combination appears twice
# Or product search returns duplicate entries

# Cause: Variant records orphaned from template or manually created

# Fix: Find and clean duplicates
# In Odoo shell:
tmpl = env['product.template'].browse(TEMPLATE_ID)
variants = tmpl.product_variant_ids
for v in variants:
    values = v.product_template_attribute_value_ids.mapped('name')
    print(f'ID {v.id}: {values}')

# Find actual DB duplicates:
SELECT product_tmpl_id,
    string_agg(ptav.name::text, ', ') as attrs,
    COUNT(*) as cnt
FROM product_product pp
JOIN product_template_attribute_value_product_product_rel rel
    ON rel.product_product_id = pp.id
JOIN product_template_attribute_value ptav
    ON ptav.id = rel.product_template_attribute_value_id
GROUP BY product_tmpl_id, pp.id
HAVING COUNT(*) > 1;

Error 3: Cannot Delete Variant

# Error: "You cannot delete a product variant that is used in..."
# Or: IntegrityError: foreign key constraint

# Cause: Variant is referenced by sales orders, invoices, or stock moves

# Fix Option 1: Archive instead of delete
# Product → product variant → Active toggle → set to Archived

# Fix Option 2: Remove the attribute value from the template
# Product Template → Attributes & Variants tab
# Remove the specific value → Odoo archives the variant

# Fix Option 3: Force delete (admin, careful)
# Only if variant has no transactions:
variant = env['product.product'].browse(VARIANT_ID)
variant.sudo().unlink()  # Will fail if referenced

Error 4: Price Extra Not Working

# Symptoms: Variant price extra is ignored, all variants show same price

# Fix: Price extra is set on the attribute value, not the variant
# Product Template → Attributes & Variants tab
# Click on the attribute → for each value, set "Value Price Extra"

# Example:
# Size S: Price Extra = 0.00 (base price)
# Size M: Price Extra = 2.00 (+$2)
# Size L: Price Extra = 5.00 (+$5)

# Note: Price Extra adds to the template's sale price
# Template price = $20, Size L extra = $5 → Variant price = $25

# If using pricelists, check that the pricelist doesn't override variant prices
# Sales → Configuration → Pricelists → check rules

Error 5: Attribute Conflict After Import

# Error after CSV import:
# "The following product template attribute values are duplicated"
# Or: IntegrityError on product_template_attribute_value

# Cause: Import created duplicate attribute-value associations

# Fix:
# 1. Export the product with variants
# 2. Check for duplicate attribute value assignments
# 3. Remove duplicates in the CSV
# 4. Re-import with External ID column for proper matching

# SQL check for duplicates:
SELECT product_tmpl_id, attribute_id, product_attribute_value_id, COUNT(*)
FROM product_template_attribute_value
GROUP BY product_tmpl_id, attribute_id, product_attribute_value_id
HAVING COUNT(*) > 1;

Error 6: Variant Stock Mismatch

# Symptoms: Template shows wrong total stock
# Individual variant quantities don't add up to template quantity

# Cause: Stock quants reference variant (product.product), not template
# Template stock is computed by summing all variant stocks

# Fix: Check stock at variant level:
SELECT pp.id, pt.name, pp.default_code,
    COALESCE(SUM(sq.quantity), 0) as on_hand
FROM product_product pp
JOIN product_template pt ON pt.id = pp.product_tmpl_id
LEFT JOIN stock_quant sq ON sq.product_id = pp.id
WHERE pt.id = TEMPLATE_ID
GROUP BY pp.id, pt.name, pp.default_code;

# If quants are wrong, do an inventory adjustment:
# Inventory → Operations → Physical Inventory
# Filter by the product, correct quantities, Apply

Error 7: Cannot Add Attribute to Existing Product

# Adding a new attribute to a product with existing transactions
# can cause issues with stock, orders, and invoices

# Fix: The safe approach
# 1. Archive the existing product
# 2. Create a new product template with all needed attributes
# 3. Migrate inventory using stock adjustments
# 4. Update references in open orders manually

# Risky but faster approach:
# Add the attribute → Odoo creates new variants
# Old variant (without new attribute) remains but may cause confusion
# Set the old variant to archived

Prevention Best Practices

  • Plan attributes before creating products — adding them later is messy
  • Use "Instantly" creation mode for physical inventory products
  • Use "Dynamically" for made-to-order or configurable products
  • Set Price Extra on attribute values, not on variants directly
  • Use barcodes on variants (not just templates) for warehouse scanning
  • Test variant generation on a small scale before bulk creating