langchain-ai/langchain · error · ValueError
Loading templates with '{template_format}' format is no long
Error message
Loading templates with '{template_format}' format is no longer supported since it can lead to arbitrary code execution. Please migrate to using the 'f-string' template format, which does not suffer from this issue. What it means
When loading a `prompt`-type config, `_load_prompt` explicitly rejects `template_format: "jinja2"` because untrusted Jinja2 templates can execute arbitrary Python code (CVE-class issue tracked in langchain issue #4394). Loading was disabled at deserialization time even though in-code Jinja2 `PromptTemplate`s still work.
Source
Thrown at libs/core/langchain_core/prompts/loading.py:206
config: dict[str, Any], *, allow_dangerous_paths: bool = False
) -> PromptTemplate:
"""Load the prompt template from config."""
# Load the template from disk if necessary.
config = _load_template(
"template", config, allow_dangerous_paths=allow_dangerous_paths
)
config = _load_output_parser(config)
template_format = config.get("template_format", "f-string")
if template_format == "jinja2":
# Disabled due to:
# https://github.com/langchain-ai/langchain/issues/4394
msg = (
f"Loading templates with '{template_format}' format is no longer supported "
f"since it can lead to arbitrary code execution. Please migrate to using "
f"the 'f-string' template format, which does not suffer from this issue."
)
raise ValueError(msg)
return PromptTemplate(**config)
@deprecated(
since="1.2.21",
removal="2.0.0",
alternative="Use `dumpd`/`dumps` from `langchain_core.load` to serialize "
"prompts and `load`/`loads` to deserialize them.",
)
def load_prompt(
path: str | Path,
encoding: str | None = None,
*,
allow_dangerous_paths: bool = False,
) -> BasePromptTemplate[str]:
"""Unified method for loading a prompt from LangChainHub or local filesystem.
View on GitHub (pinned to e32fa9a52e)
Solutions
- Rewrite the template to f-string syntax (`{var}` instead of `{{ var }}`, removing Jinja filters) and set `template_format` to `f-string` or remove the key.
- If you must use Jinja2, construct the template in code — `PromptTemplate.from_template(t, template_format='jinja2')` — from a source you trust, rather than via the config loader.
- Sanitize/audit any third-party template before hand-converting it.
Example fix
# before
# {"_type": "prompt", "template": "Hello {{ name | upper }}",
# "template_format": "jinja2", "input_variables": ["name"]}
load_prompt('prompt.json') # ValueError
# after
# {"_type": "prompt", "template": "Hello {name}",
# "input_variables": ["name"]}
load_prompt('prompt.json') Defensive patterns
Strategy: validation
Validate before calling
tf = config.get('template_format', 'f-string')
if tf == 'jinja2':
raise ValueError(
'Refusing to load jinja2 template from config (code execution risk); '
'convert to f-string first.'
)
load_prompt_from_config(config) Type guard
def is_safe_template_format(fmt: str) -> bool:
return fmt in {'f-string', 'mustache'} Prevention
- Never load Jinja2 prompt configs from untrusted sources; convert to f-string before storing.
- Audit third-party prompt packs for template_format: jinja2 before loading.
When it happens
Trigger: Loading a prompt config/Hub file whose `template_format` is `jinja2` (or omitting nothing — default is `f-string`, so only an explicit `jinja2` triggers it) via `load_prompt`/`load_prompt_from_config`.
Common situations: Legacy Hub prompts written with Jinja2; teams that preferred Jinja2 syntax and serialized prompts to disk; loading third-party prompt packs that use `{{ var }}` syntax.
Related errors
- jinja2 is unsafe and is not supported for templates expresse
- Path '{path}' is absolute. Absolute paths are not allowed wh
- Path '{path}' contains '..' components. Directory traversal
- Jinja2 templates are not allowed during deserialization for
- Loading images from 'path' has been removed as of 0.3.15 for
AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14).
Data as JSON: /api/errors/3e9173742e499663.
Report an issue: GitHub.