BerriAI/litellm · error · ValueError
Error rendering template
Error message
Error rendering template '{prompt_id}': {e} What it means
PromptManager.render wraps the Jinja2 compile-and-render step in a broad try/except and re-raises any exception as ValueError prefixed with the prompt_id. Rendering happens in an ImmutableSandboxedEnvironment with Handlebars-style delimiters ({{var}}, {% %}, {# #}), so typical causes are Jinja2 syntax errors, sandbox security rejects on unsafe attribute access, and failures raised from filters or attribute lookups during render.
Solutions
- Re-render manually to see the raw cause: jinja2.Environment().from_string(template.content).render(**vars)
- Inspect manager.prompts[prompt_id].content and fix the template syntax/delimiters
- Supply every variable the template references (or provide defaults in the template: {{var | default('x')}})
- Catch ValueError and log the chained __cause__ for the underlying Jinja2 error
Example fix
# before
rendered = manager.render('greeting', {'user': user})
# after
try:
rendered = manager.render('greeting', {'user': user})
except ValueError:
logger.exception('render failed for greeting; cause=%s', sys.exc_info()[1].__cause__)
raise Defensive patterns
Strategy: try-catch
Validate before calling
from jinja2 import Environment
def template_parses(content: str) -> bool:
try:
Environment().parse(content)
return True
except Exception:
return False
if not template_parses(manager.prompts[prompt_id].content):
raise ValueError(f'prompt {prompt_id} has invalid template syntax') Try / catch
try:
rendered = manager.render(prompt_id, variables)
except ValueError as e:
logger.error('render of %s failed: %s', prompt_id, e.__cause__ or e)
raise Prevention
- Render every loaded prompt once with sample variables as a startup smoke test
- Keep templates simple; avoid attribute chains on possibly-missing values (use {{var | default('...')}})
- Log the chained __cause__, which holds the real Jinja2 error
When it happens
Trigger: Template body with invalid Jinja2 syntax (unclosed {% if %} without {% endif %}, stray {{); accessing attributes/methods the ImmutableSandboxedEnvironment blocks; a filter applied to a variable of the wrong type; schema validation passed but the template body itself fails mid-render.
Common situations: Authoring prompts with Handlebars habits that don't map to Jinja2 blocks; using {{user.name}} where user is a plain dict key or None; escaping/whitespace edits that break delimiters; user-supplied templates submitted via a test endpoint hitting sandbox restrictions.
Related errors
- Invalid type for field
- Invalid YAML frontmatter
- Prompt directory does not exist
- prompt_id is required when prompt_file is provided
- Prompt ' ' not found. Available prompts
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/020cd5e812e79c5a.
Report an issue: GitHub.
Appendix: source
Thrown at litellm/integrations/dotprompt/prompt_manager.py:224
if template is None:
available_prompts: Final = list(self.prompts.keys())
version_str: Final = f" (version {version})" if version else ""
raise KeyError(f"Prompt '{prompt_id}'{version_str} not found. Available prompts: {available_prompts}")
variables: Final = prompt_variables or {}
# Validate input variables against schema if defined
if template.input_schema:
self._validate_input(variables, template.input_schema)
try:
# Create Jinja2 template and render
jinja_template: Final = self.jinja_env.from_string(template.content)
rendered: Final = jinja_template.render(**variables)
return rendered
except Exception as e:
raise ValueError(f"Error rendering template '{prompt_id}': {e}")
def _validate_input(self, variables: dict[str, Any], schema: dict[str, Any]) -> None:
"""Basic validation of input variables against schema."""
for field_name, field_type in schema.items():
if field_name in variables:
value = variables[field_name]
expected_type = self._get_python_type(field_type)
if not isinstance(value, expected_type):
raise ValueError(
f"Invalid type for field '{field_name}': "
f"expected {getattr(expected_type, '__name__', str(expected_type))}, got {type(value).__name__}"
)
def _get_python_type(self, schema_type: str) -> type | tuple:
"""Convert schema type string to Python type."""
type_mapping: Final[dict[str, type | tuple]] = {
"string": str,View on GitHub (pinned to 77b7c6c40c)