sqlalchemy/alembic · error · OSError
No suitable editor found. Please set the "EDITOR" or…
Error message
No suitable editor found. Please set the "EDITOR" or "VISUAL" environment variables
What it means
Raised as OSError by _find_editor when neither the EDITOR nor VISUAL environment variables are set AND none of the default editor candidates (sensible-editor, editor, nano, vim, code on POSIX; code.exe, notepad++.exe, notepad.exe on Windows) are found on PATH (editor.py:48-55). Alembic needs an editor for 'alembic edit' and interactive 'alembic revision' commands.
Solutions
- Set the EDITOR environment variable: export EDITOR=vim (or nano, code, etc.).
- Install a common editor: apt-get install vim or apt-get install nano on Debian/Ubuntu.
- Set VISUAL as an alternative: export VISUAL=code.
- Use non-interactive mode to avoid the editor entirely: alembic revision -m 'description' instead of bare alembic revision.
- For containers, add 'ENV EDITOR=vim' to the Dockerfile or install an editor in the image.
Example fix
# before alembic edit abc123 # OSError: No suitable editor found # after export EDITOR=vim alembic edit abc123 # or skip the editor entirely alembic revision -m 'add users table'
Defensive patterns
Strategy: validation
Validate before calling
import os
from os.path import exists
def ensure_editor_available(environ=None):
env = environ or os.environ
if 'EDITOR' in env or 'VISUAL' in env:
return True
from alembic.util.editor import _default_editors, _find_executable
for candidate in _default_editors():
if _find_executable(candidate, env) is not None:
return True
return False Try / catch
from alembic.util.editor import _find_editor
try:
editor = _find_editor(os.environ)
except OSError as e:
if 'No suitable editor' in str(e):
os.environ['EDITOR'] = 'vim'
editor = _find_editor(os.environ)
else:
raise Prevention
- Set EDITOR=vim (or nano) in your shell profile (~/.bashrc, ~/.zshrc).
- In Dockerfiles, install an editor: RUN apt-get install -y vim.
- Use non-interactive alembic commands (-m flag) in automation to avoid editor dependency.
When it happens
Trigger: Calling alembic edit <revision> or alembic revision (without -m) on a system where no editor is configured. The loop at editor.py:48-51 tries each default candidate via _find_executable and all return None.
Common situations: Minimal Docker/container environments with no editor installed. CI environments running interactive commands. Fresh server installs without dev tools. SSH sessions where EDITOR isn't propagated. Windows systems without VS Code or Notepad++.
Related errors
- Error executing editor
- No context has been configured yet.
- A plugin named is already registered
- Can not set dispatch function for object
- Can't change down_revision on a refresh operation.
AI-assisted analysis of sqlalchemy/alembic@5551b5d35f (2026-08-11).
Data as JSON: /api/errors/4a0b7c806fb1a0dd.
Report an issue: GitHub.
Appendix: source
Thrown at alembic/util/editor.py:52
except Exception as exc:
raise CommandError("Error executing editor (%s)" % (exc,)) from exc
def _find_editor(environ: Mapping[str, str]) -> str:
candidates = _default_editors()
for i, var in enumerate(("EDITOR", "VISUAL")):
if var in environ:
user_choice = environ[var]
if exists(user_choice):
return user_choice
if os.sep not in user_choice:
candidates.insert(i, user_choice)
for candidate in candidates:
path = _find_executable(candidate, environ)
if path is not None:
return path
raise OSError(
"No suitable editor found. Please set the "
'"EDITOR" or "VISUAL" environment variables'
)
def _find_executable(candidate: str, environ: Mapping[str, str]) -> str | None:
# Assuming this is on the PATH, we need to determine it's absolute
# location. Otherwise, ``check_call`` will fail
if not is_posix and splitext(candidate)[1] != ".exe":
candidate += ".exe"
for path in environ.get("PATH", "").split(os.pathsep):
value = join(path, candidate)
if exists(value):
return value
return None
def _default_editors() -> list[str]:View on GitHub (pinned to 5551b5d35f)