{"record":{"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/5551b5d35f985c99cb8f1af2b3c526b050e4c059/alembic/util/editor.py#L17-L53","documentation":"Raised as CommandError by open_in_editor when either _find_editor or the subprocess.check_call to launch the editor raises any exception (editor.py:31-35). This wraps the underlying error — which could be the editor binary not found, the editor exiting non-zero, the file path being invalid, or permission errors — into Alembic's CommandError with the original exception chained via 'from exc'.","triggerScenarios":"Calling alembic edit <revision> (which calls util.open_in_editor at command.py:826) when the editor process fails. Also triggered by 'alembic revision' in edit mode. The try/except at editor.py:31-35 catches all Exception subclasses including OSError, CalledProcessError, and FileNotFoundError.","commonSituations":"The EDITOR/VISUAL env var points to a binary that crashes on the file. The editor exits with a non-zero status (e.g., vim :cq). The file path contains spaces or special characters not properly escaped. Permission denied on the migration file. Editor binary exists in EDITOR but fails at runtime.","solutions":["Check the chained exception (raise ... from exc) for the root cause — run with --verbose or inspect the traceback.","Verify the EDITOR/VISUAL env var points to a working editor: echo $EDITOR && $EDITOR --version.","If the editor exited non-zero intentionally (e.g., vim :cq), fix the editor session or use a different editor.","Ensure the migration file path is accessible and writable.","Set EDITOR to a simple known-good editor like 'nano' or 'vim' to isolate the issue."],"exampleFix":"# before: EDITOR points to a broken/custom wrapper\nexport EDITOR='/usr/local/bin/my-broken-editor'\nalembic edit abc123\n\n# after\nexport EDITOR='vim'\nalembic edit abc123","handlingStrategy":"try-catch","validationCode":"import os\nfrom os.path import exists\n\ndef validate_editor_available(environ=None):\n    env = environ or os.environ\n    for var in ('EDITOR', 'VISUAL'):\n        if var in env and (exists(env[var]) or env[var]):\n            return True\n    from alembic.util.editor import _default_editors\n    for candidate in _default_editors():\n        for p in env.get('PATH', '').split(os.pathsep):\n            if exists(os.path.join(p, candidate)):\n                return True\n    return False","typeGuard":null,"tryCatchPattern":"from alembic.util.exc import CommandError\n\ntry:\n    util.open_in_editor(filepath)\nexcept CommandError as e:\n    # inspect e.__cause__ for the underlying error\n    cause = e.__cause__\n    print(f\"Editor failed: {cause}\")\n    if isinstance(cause, OSError) and 'No suitable editor' in str(cause):\n        os.environ['EDITOR'] = 'vim'\n        util.open_in_editor(filepath)\n    else:\n        raise","preventionTips":["Always set EDITOR or VISUAL in your environment.","Test that your editor can open a file non-interactively before using alembic edit.","In CI, avoid interactive commands or set EDITOR to a no-op like 'true'."],"tags":["alembic","editor","subprocess","environment","command-error"],"backgroundTag":null,"analyzedSha":"5551b5d35f985c99cb8f1af2b3c526b050e4c059","analyzedAt":"2026-08-11T01:38:46.612Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}