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

  1. 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.
  2. 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.
  3. 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

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


AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14). Data as JSON: /api/errors/3e9173742e499663. Report an issue: GitHub.