Odoo upgrade error
TypeError: object of type 'bool' has no len() (Odoo 19 reply-to)
Last updated: October 2026
Odoo 19 builds a reply-to address from a mail alias whose stored full address is empty. The value was left stale by an earlier upgrade.
This page is part of our guide on how to upgrade Odoo Community Edition. It explains what triggers the error, how to fix it by hand, and what an automated migration does about it.
The error
File ".../addons/mail/models/models.py", line ..., in _notify_get_reply_to_formatted_email
if len(record_email) >= length_limit:
TypeError: object of type 'bool' has no len()The frames above this one show the module being loaded, typically crm while it posts a tracked message on a sales team or lead.
- Raised by
_notify_get_reply_to_formatted_emailin the Odoo 19 mail module- Upgrade hops
- 18→19
- Seen when
crmloads during-u all, or later when a message is posted
When you see it
When Odoo posts a message it computes a reply-to address. For records with an e-mail alias, such as sales teams, it takes the alias's stored full address (mail_alias.alias_full_name) and checks its length. Odoo 19 does this without checking that the value is set. If the stored address is empty, len() receives False and the upgrade stops. We have seen this on several databases during the 18→19 step, always while loading crm.
Root cause
alias_full_name is a stored computed field: alias_name@domain, or just alias_name when there is no domain. It can only be empty when the alias has no name, yet the alias that crashes has one. The stored value is stale. Odoo 17 introduced alias domains (alias_domain_id); a migration that added the domain without recomputing the stored full address leaves it empty, and nothing recomputes it until Odoo 19 reads it.
Find the stale aliases in the Odoo 18 database:
SELECT a.id, a.alias_name, a.alias_full_name, d.name AS domain
FROM mail_alias a
LEFT JOIN mail_alias_domain d ON d.id = a.alias_domain_id
WHERE a.alias_name IS NOT NULL
AND a.alias_full_name IS DISTINCT FROM
CASE WHEN d.id IS NOT NULL THEN a.alias_name || '@' || d.name
ELSE a.alias_name END;How to fix it
Recompute the stored value with the same rule Odoo uses, before running the 18→19 upgrade:
Before you change anything: Back up the database before running any UPDATE or INSERT below, and try it on a copy first. These statements change data directly, outside the Odoo ORM.
-- alias with a domain: name@domain
UPDATE mail_alias a
SET alias_full_name = a.alias_name || '@' || d.name
FROM mail_alias_domain d
WHERE a.alias_domain_id = d.id
AND a.alias_name IS NOT NULL
AND a.alias_full_name IS DISTINCT FROM a.alias_name || '@' || d.name;
-- alias without a domain: just the name
UPDATE mail_alias
SET alias_full_name = alias_name
WHERE alias_name IS NOT NULL
AND alias_domain_id IS NULL
AND alias_full_name IS DISTINCT FROM alias_name;Then run the upgrade again. If the database already runs Odoo 19 and the error appears when posting messages, the same statements fix it there.
How OCU handles it
The OCU 18→19 scripts include a pre-migration step on the mail module, which loads before crm, that recomputes alias_full_name for every alias with exactly the rule above. Rows that are already correct are left alone.
A free test migration shows whether your database runs into this or any other upgrade error before you change anything on your production server.
Frequently asked questions
- Is this a bug in Odoo 19?
- Odoo 19 does not guard against an empty address there, but the empty value itself comes from stale data left by an earlier migration. With a correct stored address the code works.
- Will the fix change my aliases?
- It only rewrites the stored full address to what Odoo would compute from the alias name and domain. The alias name, the domain and the routing of incoming mail are not changed.
Related
Find upgrade errors before your production run
Upload a backup and run a free test migration. You get the upgraded database, the full log and every warning, with no change to your live system.
Start your free test migration