odoo/odoo · error · UserError
No manifest found in '%(modules)s'. Can't import the zip fil
Error message
No manifest found in '%(modules)s'. Can't import the zip file.
What it means
After extracting manifests, _import_zipfile builds the set of top-level directories in the archive and compares it with the topological sort of modules that had a recognized manifest (__manifest__.py etc.). Any directory without a manifest makes the import fail, because Odoo would import arbitrary folders as code/data with no metadata. The message lists the offending top-level directories.
Source
Thrown at addons/base_import_module/models/ir_module.py:365
dependencies = defaultdict(list)
for mod_name, manifest in manifest_files:
_manifest_path = z.extract(manifest, module_dir)
terp = Manifest._from_path(opj(module_dir, mod_name), env=self.env)
if not terp:
continue
files_to_import = terp.get('data', []) + terp.get('init_xml', []) + terp.get('update_xml', [])
if with_demo:
files_to_import += terp.get('demo', [])
for filename in files_to_import:
if os.path.splitext(filename)[1].lower() not in ('.xml', '.csv', '.sql'):
continue
module_data_files[mod_name].append('%s/%s' % (mod_name, filename))
dependencies[mod_name] = terp.get('depends', [])
dirs = {d for d in os.listdir(module_dir) if os.path.isdir(opj(module_dir, d))}
sorted_dirs = topological_sort(dependencies)
if wrong_modules := dirs.difference(sorted_dirs):
raise UserError(_(
"No manifest found in '%(modules)s'. Can't import the zip file.",
modules=", ".join(wrong_modules)
))
for file in z.infolist():
filename = file.filename
mod_name = filename.split('/')[0]
is_data_file = filename in module_data_files[mod_name]
is_static = filename.startswith('%s/static' % mod_name)
is_translation = filename.startswith('%s/i18n' % mod_name) and filename.endswith('.po')
if is_data_file or is_static or is_translation:
z.extract(file, module_dir)
for mod_name in sorted_dirs:
module_names.append(mod_name)
try:
# assert mod_name.startswith('theme_')
path = opj(module_dir, mod_name)View on GitHub (pinned to 1e661df964)
Solutions
- Re-zip so each top-level folder in the archive is a module containing __manifest__.py at its root
- Remove junk entries: __MACOSX, .DS_Store, .git, build dirs
- Fix manifest filename to exactly __manifest__.py (legacy __openerp__.py also accepted)
Example fix
# before (archive root) # parent_dir/my_module/__manifest__.py -> raises, top dir 'parent_dir' has no manifest # after zip -r my_module.zip my_module/ # archive root: my_module/__manifest__.py, my_module/models/...
Defensive patterns
Strategy: validation
Validate before calling
MANIFEST_NAMES = {'__manifest__.py', '__openerp__.py'}
def zip_layout_is_valid(data):
with zipfile.ZipFile(io.BytesIO(data)) as z:
tops = {n.split('/')[0] for n in z.namelist() if '/' in n}
manifests = {n.split('/')[0] for n in z.namelist()
if n.count('/') == 1 and n.split('/')[1] in MANIFEST_NAMES}
return tops <= manifests Prevention
- Zip from inside the parent: cd parent && zip -r mod.zip mod/
- Exclude __MACOSX, .DS_Store, .git from archives
- Name the manifest exactly __manifest__.py
When it happens
Trigger: The ZIP contains a top-level folder without __manifest__.py/__openerp__.py — e.g. zipping the parent directory so 'my_module/' sits beside '__MACOSX/', '.git/', or stray folders; or a manifest misnamed so it is not in MANIFEST_NAMES.
Common situations: 'zip -r module.zip parent_dir/' instead of zipping the module folder itself; macOS adds __MACOSX; developer renames manifest to manifest.py; nested module layout module/module/.
Related errors
- Unknown module dependencies:
- The assets path in the manifest of imported module '%(module
- Only zip files are supported.
- File '%s' exceed maximum allowed file size
- Studio customizations require the Odoo Studio app.
AI-assisted analysis of odoo/odoo@1e661df964 (2026-08-15).
Data as JSON: /api/errors/30930100f3e1b2f8.
Report an issue: GitHub.