xtekky/gpt4free · error · ImportError

Cannot find submodule

Error message

Cannot find submodule '{name}' in workspace module '{base}'.

What it means

Raised by the sandbox import hook when a dotted import's top-level module resolves to a sibling workspace .py file, but a later path component is missing as an attribute on that module. Example: 'import mypkg.helpers' where workspace contains mypkg.py but mypkg.py defines no 'helpers'. The sandbox first loads the sibling file via _load_workspace_module, then walks the remaining dotted parts with getattr and fails on the first missing attribute.

Solutions

  1. Verify the exact attribute name exists in the sibling workspace module (no typo, correct case)
  2. Import only the top-level module and access the member via attribute: 'import util; util.format_msg'
  3. Move the needed function/class into the top-level workspace .py file instead of a dotted path
  4. Ensure module-level definitions in the sibling file are unconditional (not inside try/except that swallows errors)

Example fix

# before
import helpers.format

# after (helpers.py is a flat sibling module)
import helpers
helpers.format(...)
Defensive patterns

Strategy: validation

Validate before calling

# before executing, verify the sibling module exposes the submodule name
import importlib.util, pathlib
ws = get_workspace_dir()
mod_file = ws / (base + ".py")
if mod_file.exists():
    spec = importlib.util.spec_from_file_location(base, mod_file)
    m = importlib.util.module_from_spec(spec); spec.loader.exec_module(m)
    assert hasattr(m, submodule_name), f"{base} lacks attribute {submodule_name}"

Try / catch

try:
    import mypkg.sub
except ImportError as e:
    if "Cannot find submodule" in str(e):
        import mypkg  # fall back to top-level import + attribute access

Prevention

When it happens

Trigger: A .pa.py file imports 'X.sub' where X.py exists in the workspace directory but X does not define/assign 'sub' (no submodule, class, or variable with that name). Also triggered when X.py conditionally defines 'sub' and the defining branch did not run during sandbox execution.

Common situations: Splitting a helper across several files with dotted imports as if the workspace were a package; typos in the submodule name; helper module whose import-time code raised earlier so attributes were never set.

Related errors


AI-assisted analysis of xtekky/gpt4free@973504e177 (2026-08-14). Data as JSON: /api/errors/5c39763f80d6d847. Report an issue: GitHub.

Appendix: source

Thrown at g4f/mcp/pa_provider.py:478

                    raise ImportError(
                        f"'{name}' is not available in the restricted os shim."
                    )
            return obj
        if base not in allowed:
            # Before rejecting, check if it's a workspace module (sibling .py file).
            workspace = get_workspace_dir()
            ws_module = _load_workspace_module(
                base, workspace, globals, fromlist, level
            )
            if ws_module is not None:
                # Handle submodule imports (e.g. "pkg.sub")
                if name != base:
                    # Try to resolve the full dotted path from the loaded module
                    obj = ws_module
                    for part in name.split(".")[1:]:
                        obj = getattr(obj, part, None)
                        if obj is None:
                            raise ImportError(
                                f"Cannot find submodule '{name}' in workspace module '{base}'."
                            )
                    return obj
                return ws_module
            raise ImportError(
                f"Import of '{name}' is not allowed in safe execution mode.\n"
                f"Allowed top-level modules: {', '.join(sorted(allowed))}"
            )
        # Explicit allowlist takes priority over the blocklist below.
        # This permits e.g. "g4f.Provider.helper" even though "g4f.Provider"
        # is blocked.
        for allowed_sub in _ALLOWED_G4F_SUBPATHS:
            if name == allowed_sub or name.startswith(allowed_sub + "."):
                return original(name, globals, locals, fromlist, level)
        # Block sensitive g4f submodules even though g4f itself is allowed.
        if name in _BLOCKED_SUBMODULES:
            raise ImportError(
                f"Import of '{name}' is not allowed inside a .pa.py sandbox "

View on GitHub (pinned to 973504e177)