sqlalchemy/alembic · error · CommandError
Template rendering failed; see
Error message
Template rendering failed; see %s for a template-oriented traceback.
What it means
Raised as CommandError by template_to_file when Mako template rendering fails (pyfiles.py:31-44). The function catches ALL exceptions from template.render_unicode(), writes a detailed Mako-specific traceback to a temporary .txt file, and raises CommandError pointing to that file. The temp file traceback is essential because Mako errors in the original traceback are often opaque. This is used during 'alembic init' to scaffold migration scripts and env.py from templates.
Solutions
- Open the temp file path mentioned in the error message to read the Mako-oriented traceback — it pinpoints the exact template line.
- If using a custom template (script_template.mako), validate its Mako syntax: check ${}, % directives, and <%block> tags.
- Ensure all template variables referenced in the template are provided by Alembic's init command.
- If using the default bundled template, verify the Alembic installation isn't corrupted: pip install --force-reinstall alembic.
- Check the output_encoding argument matches the template's actual encoding.
Example fix
# before: custom script_template.mako has an undefined variable
## file: my_template.mako
revision = '${revision_id}'
down_revision = '${undefined_var}' # Mako error
# after
revision = '${revision_id}'
down_revision = ${repr(down_revision)} Defensive patterns
Strategy: try-catch
Validate before calling
def validate_mako_template(template_path):
from mako.template import Template
try:
t = Template(filename=template_path)
# attempt a dry render with dummy vars
return True
except Exception:
return False Try / catch
from alembic.util.exc import CommandError
try:
command.init(config, directory)
except CommandError as e:
if 'Template rendering failed' in str(e):
# extract temp file path from error and read the Mako traceback
import re
match = re.search(r'see (.+\.txt) for', str(e))
if match:
with open(match.group(1)) as f:
print(f.read())
raise Prevention
- Validate custom Mako templates with a test render before using them with alembic init.
- Keep templates simple and ensure all referenced variables are provided by Alembic.
- After upgrading Alembic, test custom templates against the new bundled template for variable changes.
When it happens
Trigger: Calling alembic init (which calls template_to_file at command.py) when the Mako template contains syntax errors, references undefined variables, or has broken control flow. Also triggered by custom templates with incorrect ${} expressions or <%block> directives. The bare 'except:' at pyfiles.py:33 catches everything including Mako exceptions.
Common situations: Using a custom script_template.mako with Mako syntax errors. Template variables expected by the template aren't passed during init. Upgrading Alembic where the bundled template changed but a cached/custom template is stale. Encoding mismatches in the template file.
Related errors
- Error executing editor
- A plugin named is already registered
- Can not set dispatch function for object
- Can't change down_revision on a refresh operation.
- Can't drop table in batch mode
AI-assisted analysis of sqlalchemy/alembic@5551b5d35f (2026-08-11).
Data as JSON: /api/errors/e29d1d4a19dc69f0.
Report an issue: GitHub.
Appendix: source
Thrown at alembic/util/pyfiles.py:41
template_file: str | os.PathLike[str],
dest: str | os.PathLike[str],
output_encoding: str,
*,
append_with_newlines: bool = False,
**kw: Any,
) -> None:
template = Template(filename=_preserving_path_as_str(template_file))
try:
output = template.render_unicode(**kw).encode(output_encoding)
except:
with tempfile.NamedTemporaryFile(suffix=".txt", delete=False) as ntf:
ntf.write(
exceptions.text_error_template()
.render_unicode()
.encode(output_encoding)
)
fname = ntf.name
raise CommandError(
"Template rendering failed; see %s for a "
"template-oriented traceback." % fname
)
else:
with open(dest, "ab" if append_with_newlines else "wb") as f:
if append_with_newlines:
f.write("\n\n".encode(output_encoding))
f.write(output)
def coerce_resource_to_filename(fname_or_resource: str) -> pathlib.Path:
"""Interpret a filename as either a filesystem location or as a package
resource.
Names that are non absolute paths and contain a colon
are interpreted as resources and coerced to a file location.
"""View on GitHub (pinned to 5551b5d35f)