Introduction
Si vous avez déjà personnalisé Odoo ou développé des modules, il y a de fortes chances que vous ayez déjà croisé ce message déroutant.
ValueError: Expected singleton
Cette exception revient souvent lorsqu’une méthode attend de travailler sur un seul enregistrement, mais qu’elle reçoit un ensemble (recordset) contenant plusieurs éléments. Derrière le libellé technique se cache généralement une incompréhension du fonctionnement des recordsets dans l’ORM d’Odoo.
Ce guide démystifie l’erreur « Expected Singleton » : ce qu’elle signifie, d’où elle provient et comment la corriger sans casser la logique métier ni les interfaces connectées.
Que signifie « Expected Singleton » dans Odoo ?
L’ORM d’Odoo ne manipule pas des objets isolés par défaut, mais des recordsets — ensembles dynamiques d’enregistrements qui peuvent correspondre à plusieurs cas :
- Un seul enregistrement
- Plusieurs enregistrements
- Aucun enregistrement
Quand une méthode conçue pour un seul enregistrement reçoit en réalité plusieurs éléments dans le recordset, Odoo lève l’exception susmentionnée.
ValueError: Expected singleton
Pour le dire plus simplement :
Odoo attendait un unique enregistrement. Il en a reçu plusieurs.
Vous rencontrerez généralement cette erreur dans les contextes suivants :
- Les journaux serveur (logs)
- Les méthodes de modules personnalisés
- Les champs calculés (computed fields)
- Les actions déclenchées par bouton
- Les actions automatisées (automated actions)
- Les opérations en masse (bulk updates)
La clé pour résoudre proprement le problème est de bien comprendre le comportement des recordsets.
Pourquoi cette erreur survient-elle
1. Mauvaise compréhension des recordsets
Dans Odoo, self est, la plupart du temps, un recordset et non un objet unique.
Même si vous pensez manipuler un seul élément, Odoo peut appeler votre méthode avec plusieurs enregistrements lors de :
- Opérations en lot depuis la vue liste (tree view)
- Workflows automatisés
- Actions serveur
- Importations via API
Si votre code suppose qu’il n’y a qu’un seul enregistrement, il finira par casser.
2. Oublier de boucler dans la méthode
Exemple d’un comportement problématique :
def action_confirm(self): self.state = 'confirmed'
Si self regroupe plusieurs enregistrements, l’affectation est ambiguë et provoque l’erreur.
Approche correcte :
def action_confirm(self): for record in self: record.state = 'confirmed'
3. Mauvaise utilisation de ensure_one()
Odoo propose un outil pour imposer l’unicité :
self.ensure_one()
Cette méthode force l’exécution uniquement si le recordset contient exactement un enregistrement ; sinon elle lève volontairement l’erreur singleton.
N’utilisez ensure_one() que lorsque la logique métier exige strictement un seul enregistrement (par exemple l’ouverture d’un formulaire spécifique).
4. Recherches retournant plusieurs enregistrements
Exemple courant :
partner = self.env['res.partner'].search([('name', '=', 'John')])
Si plusieurs partenaires s’appellent “John” et que la suite du code attend un unique résultat, l’erreur se déclenche.
Alternative sécurisée :
partner = self.env['res.partner'].search([('name', '=', 'John')], limit=1)
5. Ambiguïté sur les champs relationnels
Les problèmes surviennent souvent autour des relations Many2one ou One2many.
Exemple courant :
Considérons : self.order_line.product_id.name
Si order_line contient plusieurs lignes, l’expression devient ambiguë et peut provoquer l’erreur.
Comment corriger l’erreur Expected Singleton
Étape 1 – Itérer sur les recordsets
Règle de base :
Considérez toujours que self peut contenir plusieurs enregistrements.
for record in self: record.process_logic()
Étape 2 – Utiliser limit=1 quand c’est pertinent
Quand seul un enregistrement a du sens dans le contexte :
record = self.env['model.name'].search(domain, limit=1)
Étape 3 – Valider les champs relationnels
Vérifiez systématiquement :
- Les relations Many2one (un vers un)
- Les collections One2many (un vers plusieurs)
- Les filtres de domaines appliqués
Assurez-vous de ne pas travailler, sans le savoir, sur plusieurs lignes.
Étape 4 – Revoir les processus d’API et d’import
Dans les environnements intégrés, les opérations en masse déclenchent souvent cette erreur parce que plusieurs enregistrements sont traités simultanément.
Si Odoo synchronise des données depuis des systèmes externes, concevez des méthodes sûres pour le traitement par lots.
Comment éviter cette erreur dans le développement Odoo
- Évitez de supposer un contexte à enregistrement unique
- Testez les méthodes avec plusieurs enregistrements sélectionnés
- Privilégiez les boucles par défaut
- Ajoutez limit=1 consciemment lorsque nécessaire
- Structurez proprement les champs relationnels
Dans des architectures complexes d’intégration, ce type d’erreur apparaît souvent lors d’imports automatisés ou de tâches planifiées. Penser ‘batch-safe’ évite des instabilités en production.
Comment Dasolo gère les erreurs liées aux recordsets et à l’ORM
L’erreur « Expected Singleton » n’est pas toujours une simple faute de code : elle met souvent en lumière des présupposés profonds sur le comportement des recordsets, l’utilisation de l’ORM et la cohérence des flux de données.
Chez Dasolo, nous traitons ces erreurs en analysant la manière dont les recordsets sont manipulés tout au long du cycle de vie du module. Les problèmes de singleton surviennent fréquemment lorsque la logique métier est prévue pour un enregistrement unique mais est exécutée sur des ensembles multiples — notamment dans les workflows automatisés, les intégrations et les champs calculés.
Pour éviter la réapparition des exceptions singleton, nous mettons l’accent sur :
- Des schémas d’itération explicites sur les recordsets
- Une utilisation réfléchie et limitée de ensure_one()
- Des filtres de domaine prévisibles et robustes
- Une architecture relationnelle claire
- Un contrôle strict des déclencheurs automatisés
Penser l’ORM pour l’évolutivité réduit significativement les erreurs inattendues en production.
Conclusion
En résumé, l’erreur « Expected Singleton » signale que du code tente d’opérer sur plusieurs enregistrements alors qu’il n’en attendait qu’un. Si elle ressemble à une erreur de débutant, elle révèle souvent des incohérences dans la gestion des recordsets ou des processus automatisés.
Comprendre le modèle de recordsets d’Odoo et appliquer des patterns sûrs d’itération permet d’éviter ce type d’erreurs. Des validations explicites, un filtrage maîtrisé et une logique d’automatisation contrôlée sont essentiels pour garder des déploiements Odoo stables et prévisibles.
Bien traitée, une exception singleton devient un indicateur utile : elle aide à renforcer la qualité du code et la fiabilité du système sur le long terme.
Questions fréquentes
Non. Elle existe sur Odoo 14, 15, 16 et 17.
Non. Il s’agit d’un problème logique dans la manière dont les enregistrements sont manipulés.
Non. Utilisez ensure_one() uniquement quand la logique métier exige absolument l’exécution sur un seul enregistrement.