p-e-w/heretic · error · ImportError

Error loading plugin '{name}': {e}

Error message

Error loading plugin '{name}': {e}

What it means

importlib.import_module() raised ImportError while importing the module part of an import-based plugin name; load_plugin() re-raises it wrapped with the original plugin name and chains the underlying exception (raise ... from e) so the root cause stays visible.

Source

Thrown at src/heretic/plugin.py:141

            sys.modules[module_name] = module
            try:
                spec.loader.exec_module(module)
            except Exception:
                sys.modules.pop(module_name, None)
                raise

        plugin_cls = validate_class(module, class_name)
    # Fully-qualified import path, e.g "heretic.scorers.keyword_rate.KeywordRate".
    else:
        if "." not in name:
            raise ValueError(
                "Import-based plugin must use the form 'fully.qualified.module.ClassName'"
            )
        module_name, class_name = name.rsplit(".", 1)
        try:
            module = importlib.import_module(module_name)
        except ImportError as e:
            raise ImportError(f"Error loading plugin '{name}': {e}") from e
        plugin_cls = validate_class(module, class_name)

    if not issubclass(plugin_cls, base_class):
        raise TypeError(f"Plugin '{name}' must subclass {base_class.__name__}")

    return plugin_cls


class Context:
    """
    Runtime context passed to plugins

    Provides plugin-safe access to the model.

    Plugins must use `get_responses(...)`, `get_logits(...)`, etc.
    Direct access to the underlying Model is intentionally not exposed.
    """

View on GitHub (pinned to bedb94ef11)

Solutions

  1. Read the chained 'from e' cause at the bottom of the traceback for the real reason.
  2. pip install the plugin package (or set PYTHONPATH) in the same environment heretic runs in.
  3. If a dependency inside the plugin is missing, install that dependency.
  4. Switch to the file-based form 'path/to/plugin.py:ClassName' if you do not want to install the package.

Example fix

# before
$ heretic --scorer mypkg.scorers.Mine.MyScorer   # ModuleNotFoundError: mypkg
# after
$ pip install -e ./mypkg
$ heretic --scorer mypkg.scorers.mine.MyScorer
Defensive patterns

Strategy: try-catch

Validate before calling

import importlib.util
def module_importable(dotted: str) -> bool:
    mod = dotted.rsplit(".", 1)[0]
    return importlib.util.find_spec(mod) is not None

Try / catch

try:
    cls = load_plugin(name, Scorer)
except ImportError as e:
    logging.exception("plugin '%s' could not be imported", name)  # chained cause included
    sys.exit(1)

Prevention

When it happens

Trigger: load_plugin('mypkg.scorers.mine.MyScorer', ...) where mypkg is not installed or not on sys.path; the module itself raises ImportError at import time (missing dependency inside the plugin); a typo in a module segment.

Common situations: Plugin package not pip-installed into the active venv; running under a different Python/venv than where the plugin is installed; plugin imports a third-party library that is missing; PYTHONPATH not set in the deployment environment.

Related errors


AI-assisted analysis of p-e-w/heretic@bedb94ef11 (2026-08-29). Data as JSON: /api/errors/14ba80ff275c101d. Report an issue: GitHub.