langchain-ai/langchain · error · ValueError

Invalid variable name {var!r} in f-string template. Variable

Error message

Invalid variable name {var!r} in f-string template. Variable names cannot be all digits as they are interpreted as positional arguments.

What it means

Raised by `validate_f_string_template` when an f-string template's variable name consists only of digits, e.g. `{0}` or `{1}`. In Python's format protocol such fields are positional arguments, but LangChain invokes formatting with keyword arguments derived from `input_variables`, so purely numeric names are unusable and rejected with `ValueError`.

Source

Thrown at libs/core/langchain_core/prompts/string.py:248

def validate_f_string_template(template: str) -> list[str]:
    """Validate an f-string template and return its input variables."""
    input_variables = set()
    for var, format_spec in _parse_f_string_fields(template):
        if "." in var or "[" in var or "]" in var:
            msg = (
                f"Invalid variable name {var!r} in f-string template. "
                f"Variable names cannot contain attribute "
                f"access (.) or indexing ([])."
            )
            raise ValueError(msg)

        if var.isdigit():
            msg = (
                f"Invalid variable name {var!r} in f-string template. "
                f"Variable names cannot be all digits as they are interpreted "
                f"as positional arguments."
            )
            raise ValueError(msg)

        if format_spec and ("{" in format_spec or "}" in format_spec):
            msg = (
                "Invalid format specifier in f-string template. "
                "Nested replacement fields are not allowed."
            )
            raise ValueError(msg)

        input_variables.add(var)

    return sorted(input_variables)


def check_valid_template(
    template: str, template_format: str, input_variables: list[str]
) -> None:
    """Check that template string is valid.

View on GitHub (pinned to e32fa9a52e)

Solutions

  1. Rename the placeholders to descriptive identifiers: `"{speaker} said: {utterance}"`, and pass those names as format kwargs
  2. If the values genuinely come from a list, unpack them into named locals first (`speaker, utterance = rows[0]`) and format with names
  3. If positional formatting must be preserved, format the string yourself before constructing the template

Example fix

# before
prompt = PromptTemplate.from_template("{0}: {1}")

# after
prompt = PromptTemplate.from_template("{speaker}: {utterance}")
prompt.format(speaker="Ada", utterance="hello")
Defensive patterns

Strategy: validation

Validate before calling

import re

def has_no_numeric_vars(template: str) -> bool:
    return not any(v.isdigit() for v in re.findall(r"\{(\w+)\}", template))

assert has_no_numeric_vars(template)

Prevention

When it happens

Trigger: A template like `"{0} said: {1}"` passed to `PromptTemplate.from_template(...)` (default f-string format), or to `validate_f_string_template` / `get_template_variables(..., "f-string")`. The `var.isdigit()` check fires for each parsed field.

Common situations: Translating `str.format`-style code or `.format(*args)` call sites into prompt templates; auto-generated templates that number placeholders; templates converted from CSV/JSON resources that use positional markers.

Related errors


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