langchain-ai/langchain · critical · ValueError
Jinja2 templates are not allowed during deserialization for
Error message
Jinja2 templates are not allowed during deserialization for security reasons. Use 'f-string' template format instead, or explicitly allow jinja2 by providing a custom init_validator.
What it means
Security guard raised during deserialization when a serialized PromptTemplate (or similar) has template_format='jinja2'. Jinja2 template rendering can execute arbitrary expressions, so loading untrusted serialized payloads with jinja2 is blocked by default; the init_validator raises before the class is even imported.
Source
Thrown at libs/core/langchain_core/load/load.py:248
We intentionally do NOT check the `class_path` here to keep this simple and
future-proof. If any new class is added that accepts `template_format='jinja2'`,
it will be automatically blocked without needing to update this function.
Args:
class_path: The class path tuple being deserialized (unused).
kwargs: The kwargs dict for the class constructor.
Raises:
ValueError: If `template_format` is `'jinja2'`.
"""
_ = class_path # Unused - see docstring for rationale. Kept to satisfy signature.
if kwargs.get("template_format") == "jinja2":
msg = (
"Jinja2 templates are not allowed during deserialization for security "
"reasons. Use 'f-string' template format instead, or explicitly allow "
"jinja2 by providing a custom init_validator."
)
raise ValueError(msg)
def default_init_validator(
class_path: tuple[str, ...],
kwargs: dict[str, Any],
) -> None:
"""Default init validator that blocks jinja2 templates.
This is the default validator used by `load()` and `loads()` when no custom
validator is provided.
Args:
class_path: The class path tuple being deserialized.
kwargs: The kwargs dict for the class constructor.
Raises:
ValueError: If template_format is `'jinja2'`.
"""View on GitHub (pinned to e32fa9a52e)
Solutions
- Re-create the template with f-string format and re-serialize: PromptTemplate.from_template(t, template_format='f-string')
- If the payload is fully trusted, supply a custom init_validator to loads/loads that permits jinja2
- Migrate stored workflows once, then persist the f-string versions
Example fix
# before obj = loads(legacy_payload) # payload has template_format='jinja2' # after from langchain_core.load.load import default_init_validator def allow_jinja2(class_path, kwargs): pass # trusted payloads only obj = loads(legacy_payload, init_validator=allow_jinja2)
Defensive patterns
Strategy: validation
Validate before calling
import json
payload = json.loads(text)
def scan_for_jinja2(node):
if isinstance(node, dict):
if node.get('kwargs', {}).get('template_format') == 'jinja2' if isinstance(node.get('kwargs'), dict) else False:
return True
return any(scan_for_jinja2(v) for v in node.values())
if isinstance(node, list):
return any(scan_for_jinja2(v) for v in node)
return False
if scan_for_jinja2(payload):
raise ValueError('payload contains jinja2 templates; migrate or supply custom init_validator') Try / catch
try:
obj = loads(text)
except ValueError as e:
if 'Jinja2' in str(e) and payload_is_trusted:
obj = loads(text, init_validator=lambda cp, kw: None)
else:
raise Prevention
- Default new templates to template_format='f-string'
- Only override init_validator for payloads whose provenance you fully control
- Scan untrusted payloads for template_format='jinja2' before loading
When it happens
Trigger: loads(serialized_json) where the payload contains kwargs with "template_format": "jinja2" — e.g. a chain serialized by an older LangChain version that defaulted to jinja2 templates. Also triggered by hand-crafted payloads targeting PromptTemplate.
Common situations: Loading legacy serialized chains from LangChain <0.0.250-ish versions where jinja2 was a common default; restoring snapshots/dumps from other teams; prompt-injection-style malicious payloads from untrusted storage.
Related errors
- Deserialization of {mapping_key!r} is not allowed. The defau
- Invalid namespace: {value}
- jinja2 is unsafe and is not supported for templates expresse
- Loading templates with '{template_format}' format is no long
- invalid IP address
AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14).
Data as JSON: /api/errors/db34ce6f4f7c97ea.
Report an issue: GitHub.