Introdução
Se já trabalhou com Odoo por tempo suficiente, é provável que se tenha deparado com a mensagem assustadora:
ValueError: Expected singleton
Este é um dos erros mais frequentes ligados ao ORM do Odoo. Surge quando uma função espera operar sobre um único registo, mas acaba por receber vários. Embora a mensagem pareça técnica, a origem é normalmente simples quando compreendemos como os recordsets do Odoo funcionam.
Este artigo descreve o que significa o erro “Expected Singleton”, por que acontece e como corrigir o problema de forma segura sem comprometer a lógica de negócio ou as integrações.
O que significa “Expected Singleton” no Odoo?
No Odoo, o ORM (Object Relational Mapping) não trabalha por defeito com objectos isolados. Em vez disso, manipula coleções — os chamados recordsets — que podem representar:
- Um único registo
- Vários registos
- Nenhum registo
Quando o Odoo executa um método pensado para um único registo, mas o recordset tem vários, é gerado o seguinte erro:
ValueError: Expected singleton
Em termos simples:
O Odoo esperava um registo. Recebeu vários.
Normalmente encontra-se este erro em situações como:
- Registos nos logs do servidor
- Métodos de módulos personalizados
- Campos computados
- Ações associadas a botões
- Ações automatizadas
- Atualizações em massa
Compreender como os recordsets se comportam é essencial para resolver o problema de forma correta.
Por que este erro ocorre
1. Falhas de entendimento sobre recordsets
No Odoo, o parâmetro self é, na maioria dos casos, um recordset.
Mesmo que pareça que está a trabalhar num único registo, o Odoo pode chamar o seu método com vários registos, por exemplo durante:
- Operações em lote na vista de lista
- Workflows automáticos
- Ações de servidor
- Importações via API
Se o seu código assume sempre um registo único, vai falhar quando o contexto trouxer vários.
2. Falta de iteração dentro do método
Exemplo de código problemático:
def action_confirm(self): self.state = 'confirmed'
Se self representar vários registos, a atribuição torna-se ambígua e dispara o erro.
Abordagem correta:
def action_confirm(self): for record in self: record.state = 'confirmed'
3. Uso indevido de ensure_one()
O Odoo disponibiliza uma ferramenta útil:
self.ensure_one()
Esta chamada força que o método só execute quando há exactamente um registo; caso contrário, lança deliberadamente o erro singleton.
Utilize ensure_one() apenas quando a lógica de negócio exigir estritamente um único registo (por exemplo, abrir um formulário específico).
4. Searches que devolvem vários registos
Exemplo:
partner = self.env['res.partner'].search([('name', '=', 'John')])
Se existirem vários registos “John” e o código subsequente pressupõe apenas um, surgirá o erro.
Alternativa mais segura:
partner = self.env['res.partner'].search([('name', '=', 'John')], limit=1)
5. Ambiguidade em campos relacionais
Muitos erros envolvem campos Many2one ou One2many.
Exemplo:
Exemplo comum: self.order_line.product_id.name
Se order_line tiver várias linhas, a expressão é ambígua e pode originar problemas.
Como corrigir o erro Expected Singleton
Passo 1 – Percorrer recordsets
Regra prática no Odoo:
Presuma sempre que self pode conter vários registos.
for record in self: record.process_logic()
Passo 2 – Usar limit=1 quando apropriado
Quando apenas um registo faz sentido do ponto de vista da lógica:
record = self.env['model.name'].search(domain, limit=1)
Passo 3 – Validar campos relacionais
Verifique:
- Relações Many2one
- Colecções One2many
- Filtros de domínio
Assegure-se de não estar involuntariamente a manipular múltiplas linhas.
Passo 4 – Rever processos de API e importação
Em ambientes com muitas integrações, operações em lote tendem a desencadear este erro porque vários registos são processados de uma vez.
Se a sua instância Odoo sincroniza dados com sistemas externos, garanta que a lógica é segura para operações em lote.
Como evitar este erro no desenvolvimento Odoo
- Evite assumir contexto de registo único
- Teste métodos com vários registos selecionados
- Adote loops por defeito
- Use limit=1 de forma consciente
- Organize campos relacionais de forma clara
Em integrações complexas, estes problemas aparecem frequentemente em importações automáticas ou tarefas agendadas. Conceber métodos à prova de lote evita instabilidade.
Como a Dasolo trata erros relacionados a recordsets e ao ORM
O erro “Expected Singleton” raramente é apenas um engano de programação. Em ambientes Odoo estruturados, costuma revelar pressupostos mais profundos sobre o comportamento dos recordsets, o uso do ORM e a consistência do fluxo de dados.
Na Dasolo, abordamos erros do ORM analisando como os recordsets são tratados ao longo do ciclo de vida dos módulos. Problemas de singleton surgem quando a lógica de negócio foi escrita para casos de um único registo, mas é executada sobre conjuntos múltiplos — especialmente em workflows automáticos, integrações ou campos computados.
Para evitar que as exceções singleton se repitam, focamo-nos em:
- Padrões explícitos de iteração de recordsets
- Uso controlado de ensure_one()
- Filtros de domínio previsíveis
- Arquitectura relacional limpa
- Controlo rigoroso dos gatilhos automatizados
Projetar a lógica do ORM com escalabilidade em mente reduz substancialmente erros inesperados em produção.
Conclusão
O “Expected Singleton” no Odoo é uma exceção comum do ORM que surge quando o código tenta operar sobre múltiplos registos enquanto espera apenas um. Embora muitas vezes pareça um descuido do programador, indica inconsistências no tratamento de recordsets em módulos personalizados ou processos automatizados.
Compreendendo como o ORM do Odoo gere recordsets e aplicando padrões seguros de iteração, os desenvolvedores podem evitar a recorrência deste erro. Tratamento estruturado dos registos, validações explícitas e lógica de automação controlada são essenciais para deployments Odoo estáveis e previsíveis.
Quando tratado corretamente, o erro singleton transforma-se num sinal útil para reforçar a qualidade do código e a fiabilidade do sistema a longo prazo.
Perguntas frequentes
Não. Aparece em Odoo 14, 15, 16 e 17.
Não. Trata-se de uma questão lógica sobre como os registos são manipulados.
Não. Use-o apenas quando a lógica de negócio exigir execução estritamente para um único registo.