PrefectHQ/fastmcp · error · ImportError

Failed to execute module

Error message

Failed to execute module {file_path}: {e}

What it means

First-time import path: after building the module from the spec, `spec.loader.exec_module(module)` raised. FastMCP pops the half-initialized module from sys.modules (so retries start clean) and wraps any exception in this ImportError.

Solutions

  1. Read the chained cause for the real exception and fix the plugin file
  2. Run `python -m py_compile plugin.py` to catch syntax errors early
  3. Move side-effectful code out of module scope into functions or `if __name__ == '__main__':`
  4. Install missing dependencies; since sys.modules is cleaned up, simply retry discovery after fixing

Example fix

// before
# plugin.py
cfg = open('/etc/missing.conf').read()  # FileNotFoundError at import
// after
# plugin.py
def load_cfg():
    return open('/etc/missing.conf').read()
Defensive patterns

Strategy: try-catch

Validate before calling

import py_compile; py_compile.compile(str(path), doraise=True)

Try / catch

try:
    mod = provider.import_module_from_file(path)
except ImportError as e:
    log.error('exec of %s failed: %s', path, e.__cause__)
    # sys.modules is cleaned up; safe to retry after fixing the file

Prevention

When it happens

Trigger: Executing a plugin file for the first time where module-level code raises anything: SyntaxError, ImportError, NameError, or a runtime error at import time.

Common situations: Newly added tool files with syntax errors; dependencies missing in the deployment env; module-level `open()`/network calls failing; Python version incompatibilities in the plugin.

Related errors


AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29). Data as JSON: /api/errors/a95f4a696d051e6e. Report an issue: GitHub.

Appendix: source

Thrown at fastmcp_slim/fastmcp/server/providers/filesystem_discovery.py:276

                existing.__loader__ = spec.loader
                existing.__file__ = str(file_path)
                try:
                    spec.loader.exec_module(existing)
                except Exception as e:
                    raise ImportError(
                        f"Failed to reload module {file_path}: {e}"
                    ) from e
                return existing

            module = importlib.util.module_from_spec(spec)
            sys.modules[module_name] = module

            try:
                spec.loader.exec_module(module)
            except Exception as e:
                # Clean up sys.modules on failure
                sys.modules.pop(module_name, None)
                raise ImportError(f"Failed to execute module {file_path}: {e}") from e

            return module
        finally:
            if path_added:
                with contextlib.suppress(ValueError):
                    sys.path.remove(parent_dir)


def extract_components(module: ModuleType) -> list[FastMCPComponent]:
    """Extract all MCP components from a module.

    Scans all module attributes for instances of Tool, Resource,
    ResourceTemplate, or Prompt objects created by standalone decorators,
    or functions decorated with @tool/@resource/@prompt that have __fastmcp__ metadata.

    Args:
        module: The imported module to scan.

View on GitHub (pinned to 1f02114297)