xtekky/gpt4free · error · ValueError

File must have .pa.py extension

Error message

File must have .pa.py extension: {file_path}

What it means

Raised by load_pa_provider when the file exists but its name does not end with '.pa.py'. The double extension is the convention that marks a file as a sandboxed PA provider; plain '.py' files are rejected so they cannot be confused with trusted code.

Solutions

  1. Rename the file to end in .pa.py (e.g. myprov.pa.py)
  2. Validate the suffix in your own tooling before calling load: p.name.endswith('.pa.py')

Example fix

# before
load_pa_provider(ws / 'myprov.py')

# after
load_pa_provider(ws / 'myprov.pa.py')
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path
assert Path(file_path).name.endswith('.pa.py'), "PA providers must end in .pa.py"

Try / catch

try:
    provider_cls = load_pa_provider(path)
except ValueError:
    path = path.with_name(path.stem + '.pa.py')  # or reject the registration

Prevention

When it happens

Trigger: Passing 'myprov.py', 'provider.txt' or any file whose Path.name doesn't end with '.pa.py' to load_pa_provider.

Common situations: Renaming existing provider modules without adding the .pa.py suffix; automation that strips or rewrites extensions; copy-paste from examples that used plain .py files.

Related errors


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

Appendix: source

Thrown at g4f/mcp/pa_provider.py:748

    with a ``create_completion`` or ``create_async_generator`` attribute is
    returned instead.

    Args:
        file_path: Path to the ``.pa.py`` file.

    Returns:
        The provider class, or ``None`` if none could be found.

    Raises:
        FileNotFoundError: If *file_path* does not exist.
        ValueError: If *file_path* does not end with ``.pa.py``.
        RuntimeError: If the file fails to execute.
    """
    file_path = Path(file_path)
    if not file_path.exists():
        raise FileNotFoundError(f"PA provider file not found: {file_path}")
    if not file_path.name.endswith(".pa.py"):
        raise ValueError(f"File must have .pa.py extension: {file_path}")

    code = file_path.read_text(encoding="utf-8")
    result = execute_safe_code(code, file_path=file_path, timeout=0.1, max_depth=100)

    if not result.success:
        raise RuntimeError(
            f"Failed to load PA provider from {file_path}:\n{result.error}"
        )

    # Prefer an explicit 'Provider' name
    provider_class = result.locals.get("Provider")
    if provider_class is not None:
        return provider_class

    # Fall back to any class that looks like a provider
    for obj in result.locals.values():
        if isinstance(obj, type) and (
            hasattr(obj, "create_completion") or hasattr(obj, "create_async_generator")

View on GitHub (pinned to 973504e177)