celery/celery · error · NotAPackage

Error: Module '{module}' doesn't exist, or it's not a valid

Error message

Error: Module '{module}' doesn't exist, or it's not a valid Python module name.

What it means

BaseLoader._import_config_module calls find_module(name); if it raises NotAPackage (the path is not a valid importable package/module), the loader raises NotAPackage with a message that the module doesn't exist or isn't a valid name. If the name ends in '.py', it additionally suggests the suffix-stripped name, since users commonly include the extension.

Source

Thrown at celery/loaders/base.py:154

            # here (e.g., ``os.path:abspath``).
            return symbol_by_name(path, imp=imp)

        # Not sure if path is just a module name or if it includes an
        # attribute name (e.g., ``os.path``, vs, ``os.path.abspath``).
        try:
            return imp(path)
        except ImportError:
            # Not a module name, so try module + attribute.
            return symbol_by_name(path, imp=imp)

    def _import_config_module(self, name):
        try:
            self.find_module(name)
        except NotAPackage as exc:
            if name.endswith('.py'):
                reraise(NotAPackage, NotAPackage(CONFIG_WITH_SUFFIX.format(
                        module=name, suggest=name[:-3])), sys.exc_info()[2])
            raise NotAPackage(CONFIG_INVALID_NAME.format(module=name)) from exc
        else:
            return self.import_from_cwd(name)

    def find_module(self, module):
        return find_module(module)

    def cmdline_config_parser(self, args, namespace='celery',
                              re_type=re.compile(r'\((\w+)\)'),
                              extra_types=None,
                              override_types=None):
        extra_types = extra_types if extra_types else {'json': json.loads}
        override_types = override_types if override_types else {
            'tuple': 'json',
            'list': 'json',
            'dict': 'json'
        }
        from celery.app.defaults import NAMESPACES, Option
        namespace = namespace and namespace.lower()

View on GitHub (pinned to 571efe8120)

Solutions

  1. Verify the module is importable: `python -c "import myconfig"` from the worker's cwd
  2. Remove any `.py` suffix from CELERY_CONFIG_MODULE (use `myconfig`, not `myconfig.py`)
  3. Ensure the directory containing the config module is on PYTHONPATH or is the cwd
  4. Check for typos in the module path

Example fix

// before
export CELERY_CONFIG_MODULE=myconfig.py  # NotAPackage

// after
export CELERY_CONFIG_MODULE=myconfig
Defensive patterns

Strategy: validation

Validate before calling

import os, importlib
name = os.environ.get('CELERY_CONFIG_MODULE')
if name:
    name = name[:-3] if name.endswith('.py') else name
    try:
        importlib.import_module(name)
    except ImportError as e:
        raise SystemExit(f'CELERY_CONFIG_MODULE {name!r} is not importable: {e}')

Try / catch

from celery.utils.imports import NotAPackage
try:
    app.loader._import_config_module(name)
except NotAPackage as e:
    if name.endswith('.py'):
        os.environ['CELERY_CONFIG_MODULE'] = name[:-3]
    raise

Prevention

When it happens

Trigger: Setting CELERY_CONFIG_MODULE to a module that doesn't exist on sys.path; including a `.py` extension in the module name; giving a path with invalid characters for a Python module.

Common situations: Wrong CELERY_CONFIG_MODULE value; config module not on PYTHONPATH; typo; including file extension like `myconfig.py`; running from a different working directory.

Related errors


AI-assisted analysis of celery/celery@571efe8120 (2026-08-04). Data as JSON: /data/errors/4d0c9a9e2198e071.json. Report an issue: GitHub.