Skip to content

Windows Path Bug Report: Jupyter Commands Fail with Special Characters in Username #442

@michaelhidalgo

Description

@michaelhidalgo

Summary

Jupyter commands fail on Windows when the current working directory path contains special characters (specifically parentheses) in the username, even when Python and Jupyter are properly installed and accessible.

Problem Description

When running Jupyter commands from a directory path containing parentheses in the Windows username, the command execution fails with:

'C:\Users\JohnDoe' is not recognized as an internal or external command,
operable program or batch file.

Reproduction Steps

Failing Case

C:\Users\JohnDoe(TEST)>python.exe -m jupyter notebook --no-browser
'C:\Users\JohnDoe' is not recognized as an internal or external command,
operable program or batch file.

Working Case (Same System, Different Directory)

C:\Users\JohnDoe(TEST)\AppData\Local\env\tools>python.exe -m jupyter notebook --no-browser
[I 2024-xx-xx xx:xx:xx.xxx NotebookApp] Serving notebooks from local directory: C:\Users\JohnDoe(TEST)\AppData\Local\env\tools
[... works fine ...]

Root Cause Analysis

The issue occurs in jupyter_core/command.py in the _execvp() function. On Windows, when executing subcommands, the function constructs a command line without properly quoting paths that contain special characters.

Technical Details

  • Location: jupyter_core/command.py, lines 114-137, specifically line 127
  • Issue: Unquoted command paths with parentheses cause Windows to interpret C:\Users\JohnDoe(TEST)\path\to\jupyter-notebook.exe as C:\Users\JohnDoe (stopping at the parenthesis)
  • Platform: Windows-specific issue due to how subprocess.Popen handles unquoted paths with shell=True

Proposed solution

Updated the command line construction to properly quote both the command path and arguments:

def _execvp(cmd: str, argv: list[str]) -> None:
    """execvp, except on Windows where it uses Popen

    Python provides execvp on Windows, but its behavior is problematic (Python bug#9148).
    """
    if sys.platform.startswith("win"):
        # PATH is ignored when shell=False,
        # so rely on shutil.which
        cmd_path = which(cmd)
        if cmd_path is None:
            msg = f"{cmd!r} not found"
            raise OSError(msg, errno.ENOENT)

        # Quote the command path and arguments to handle Windows paths with special characters
        cmd_line = f'"{cmd_path}"' + ''.join(f' "{arg}"' for arg in argv[1:])
        p = Popen(cmd_line, shell=True)  # noqa: S602

        # Don't raise KeyboardInterrupt in the parent process.
        # Set this after spawning, to avoid subprocess inheriting handler.
        import signal

        signal.signal(signal.SIGINT, signal.SIG_IGN)
        p.wait()
        sys.exit(p.returncode)
    else:
        os.execvp(cmd, argv)  # noqa: S606

Impact

  • Affected Users: Windows users with special characters (parentheses, spaces) in their username or installation paths
  • Scope: All Jupyter subcommands (jupyter notebook, jupyter lab, jupyter kernelspec, etc.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions