{"id":"1df2bf42f5121016","repo":"sqlalchemy/alembic","slug":"error-executing-editor-s","errorCode":null,"errorMessage":"Error executing editor (%s)","messagePattern":"Error executing editor \\((.+?)\\)","errorType":"exception","errorClass":"CommandError","httpStatus":null,"severity":"error","filePath":"alembic/util/editor.py","lineNumber":35,"sourceCode":"    \"\"\"\n    Opens the given file in a text editor. If the environment variable\n    ``EDITOR`` is set, this is taken as preference.\n\n    Otherwise, a list of commonly installed editors is tried.\n\n    If no editor matches, an :py:exc:`OSError` is raised.\n\n    :param filename: The filename to open. Will be passed  verbatim to the\n        editor command.\n    :param environ: An optional drop-in replacement for ``os.environ``. Used\n        mainly for testing.\n    \"\"\"\n    env = os.environ if environ is None else environ\n    try:\n        editor = _find_editor(env)\n        check_call([editor, filename])\n    except Exception as exc:\n        raise CommandError(\"Error executing editor (%s)\" % (exc,)) from exc\n\n\ndef _find_editor(environ: Mapping[str, str]) -> str:\n    candidates = _default_editors()\n    for i, var in enumerate((\"EDITOR\", \"VISUAL\")):\n        if var in environ:\n            user_choice = environ[var]\n            if exists(user_choice):\n                return user_choice\n            if os.sep not in user_choice:\n                candidates.insert(i, user_choice)\n\n    for candidate in candidates:\n        path = _find_executable(candidate, environ)\n        if path is not None:\n            return path\n    raise OSError(\n        \"No suitable editor found. Please set the \"","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/sqlalchemy/alembic/blob/44fb3450330204b222ff05135e1fbbbdb28c44db/alembic/util/editor.py#L17-L53","documentation":"Raised as CommandError in open_in_editor (editor.py:35) wrapping ANY exception that escapes _find_editor or subprocess.check_call when launching the configured editor. It re-raises the original as __cause__ so the underlying failure (FileNotFoundError, non-zero editor exit, permission error) is preserved in the traceback.","triggerScenarios":"Running `alembic edit <revision>` or any code path that calls open_in_editor when the editor binary exists but fails to run, exits non-zero, or the target file path is invalid. The message interpolates the wrapped exception's repr.","commonSituations":"EDITOR set to a GUI editor (code, subl) that returns before the file is closed and Alembic reads it; editor exits non-zero due to a config problem; the migration file path passed to the editor is missing or unreadable; running in a container without an interactive TTY.","solutions":["Check the wrapped exception (the '(FileNotFoundError ...)' or exit-code text) to see what actually failed.","Set EDITOR to a blocking terminal editor (e.g. nano, vim) for non-GUI environments: `export EDITOR=nano`.","Ensure an interactive TTY is available (run in a real terminal, not a detached CI shell) when invoking edit.","Verify the migration file the editor was asked to open actually exists."],"exampleFix":"# before: EDITOR points to a non-blocking GUI editor that exits immediately\nexport EDITOR=code\nalembic edit abc123\n# after: use a blocking editor\nexport EDITOR=nano\nalembic edit abc123","handlingStrategy":"try-catch","validationCode":"import os, shutil\ndef editor_is_callable() -> bool:\n    ed = os.environ.get('EDITOR') or os.environ.get('VISUAL')\n    return bool(ed and (os.path.exists(ed) or shutil.which(ed)))\n\nif not editor_is_callable():\n    raise SystemExit('EDITOR not usable; set it before running alembic edit')","typeGuard":null,"tryCatchPattern":"from alembic.util.exc import CommandError\ntry:\n    command.edit(cfg, revision)\nexcept CommandError as e:\n    if 'Error executing editor' in str(e):\n        print(f'Editor failed: {e.__cause__}. Set EDITOR to a blocking terminal editor.')\n    else:\n        raise","preventionTips":["Set EDITOR to a blocking, terminal-based editor in your shell profile.","Ensure an interactive TTY is present when invoking alembic edit.","For non-interactive scripts, avoid --edit and pass -m directly."],"tags":["alembic","editor","subprocess","environment","command"],"analyzedSha":"44fb3450330204b222ff05135e1fbbbdb28c44db","analyzedAt":"2026-08-04T19:57:10.248Z","schemaVersion":2}