xtekky/gpt4free · error · PermissionError

Invalid file path: '{file}'

Error message

Invalid file path: '{file}'

What it means

Raised by the sandbox open() shim when Path(file).resolve() itself raises ValueError or OSError — i.e. the path is malformed before any containment check happens. Typical causes: embedded NUL bytes, paths too long for the OS, or (on Windows) paths with invalid characters or nonexistent drive roots. The original exception is chained via 'from exc'.

Source

Thrown at g4f/mcp/pa_provider.py:543

        k: getattr(_builtins, k) for k in dir(_builtins) if k not in _blocked
    }

    # Provide a workspace-scoped open()
    def _safe_open(file, mode="r", *args, **kwargs):
        """open() restricted to the workspace directory."""
        path = Path(file)
        if not path.is_absolute():
            path = workspace / path
        try:
            resolved = path.resolve()
            ws_resolved = workspace.resolve()
            if not str(resolved).startswith(str(ws_resolved)):
                raise PermissionError(
                    f"File access outside workspace is denied: '{file}'. "
                    f"Workspace: {workspace}"
                )
        except (ValueError, OSError) as exc:
            raise PermissionError(f"Invalid file path: '{file}'") from exc
        return open(resolved, mode, *args, **kwargs)

    safe_builtins["open"] = _safe_open
    safe_builtins["__import__"] = _make_restricted_import(allowed)

    # Override print / input so stdout/stderr stay local to this sandbox
    # execution and are never written to the real sys.stdout/stderr.  This
    # avoids the global-state side-effect that contextlib.redirect_stdout
    # would cause when the thread is abandoned after a timeout.
    if stdout_buf is not None:
        _real_print = _builtins.print

        def _safe_print(*args, **kwargs):
            kwargs.setdefault("file", stdout_buf)
            _real_print(*args, **kwargs)

        safe_builtins["print"] = _safe_print

View on GitHub (pinned to 973504e177)

Solutions

  1. Sanitize filenames before open(): strip control characters and NULs
  2. Print/log the exact file value to find which call site produced the bad path
  3. Construct paths with pathlib.Path components instead of string concatenation

Example fix

# before
name = user_input  # may contain \x00
open(name)

# after
name = user_input.replace('\x00', '')
open(name)
Defensive patterns

Strategy: validation

Validate before calling

def safe_filename(name: str) -> str:
    return ''.join(ch for ch in name if ord(ch) > 31 and ch not in '<>:"/\\|?*')

Try / catch

try:
    f = open(user_path)
except PermissionError as e:
    if "Invalid file path" in str(e):
        user_path = safe_filename(user_path); f = open(user_path)

Prevention

When it happens

Trigger: open('data\x00.json'), an extremely long relative path that exceeds PATH_MAX during resolution, or a path containing characters the filesystem API rejects so that resolve() throws OSError/ValueError.

Common situations: Binary data or user input containing NUL bytes concatenated into a filename; machine-generated paths from LLM-written provider code; cross-platform scripts with Windows-invalid characters (* ? " < > |) in names.

Related errors


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