pypa/pip · error · PipError

Editor Subprocess exited with exit code {e.returncode}

Error message

Editor Subprocess exited with exit code {e.returncode}

What it means

Raised by ConfigurationCommand.open_in_editor when the editor subprocess returns a non-zero exit code (subprocess.CalledProcessError). pip wraps the failure into a PipError reporting the editor's return code, because 'pip config edit' shells out via subprocess.check_call('{editor} "{fname}"', shell=True).

Source

Thrown at src/pip/_internal/commands/configuration.py:254

        fname = self.configuration.get_file_to_edit()
        if fname is None:
            raise PipError("Could not determine appropriate file.")
        elif '"' in fname:
            # This shouldn't happen, unless we see a username like that.
            # If that happens, we'd appreciate a pull request fixing this.
            raise PipError(
                f'Can not open an editor for a file name containing "\n{fname}'
            )

        try:
            subprocess.check_call(f'{editor} "{fname}"', shell=True)
        except FileNotFoundError as e:
            if not e.filename:
                e.filename = editor
            raise
        except subprocess.CalledProcessError as e:
            raise PipError(f"Editor Subprocess exited with exit code {e.returncode}")

    def _get_n_args(self, args: list[str], example: str, n: int) -> Any:
        """Helper to make sure the command got the right number of arguments"""
        if len(args) != n:
            msg = (
                f"Got unexpected number of arguments, expected {n}. "
                f'(example: "{get_prog()} config {example}")'
            )
            raise PipError(msg)

        if n == 1:
            return args[0]
        else:
            return args

    def _save_configuration(self) -> None:
        # We successfully ran a modifying command. Need to save the
        # configuration.

View on GitHub (pinned to d7d0d0a394)

Solutions

  1. Re-run the edit and ensure the editor exits cleanly (e.g. in vim use :wq not :cq).
  2. Check the file is writable: 'ls -l <config-file>' and fix permissions.
  3. Set EDITOR to a reliable terminal editor: export EDITOR=nano or export EDITOR='vim'.
  4. For GUI editors that fork, configure them to foreground, or edit the file directly.

Example fix

// before
# EDITOR='code --wait' returns non-zero in some shells
pip config edit
// after
export EDITOR=vim
pip config edit
Defensive patterns

Strategy: try-catch

Validate before calling

import shutil, os
editor = os.environ.get("VISUAL") or os.environ.get("EDITOR") or ""
if editor and not shutil.which(editor.split()[0]):
    raise SystemExit(f"EDITOR {editor!r} not found on PATH")

Try / catch

# subprocess.run + check returncode yourself instead of relying on pip's wrapper
import subprocess
rc = subprocess.call([editor, fname])
if rc != 0:
    print(f"editor exited {rc}; config not saved reliably", file=sys.stderr)

Prevention

When it happens

Trigger: The chosen editor (from --editor, $VISUAL, or $EDITOR) launched but exited non-zero: the user closed it with an error, it failed to save, or it printed an error and quit. Note: a missing editor binary raises FileNotFoundError instead (re-raised), not this error.

Common situations: EDITOR pointing to a GUI editor that forks and returns immediately with a non-zero status; an editor that errors on the file (permissions, read-only); vim/nano exited via :cq (exit code 1); a wrapper script that returns non-zero on success.

Related errors


AI-assisted analysis of pypa/pip@d7d0d0a394 (2026-08-04). Data as JSON: /data/errors/b75f28a8cdf86fea.json. Report an issue: GitHub.