langchain-ai/langchain · error · ChevronError
Trying to close tag "{tag_key}"\nlast open tag is "{last_sec
Error message
Trying to close tag "{tag_key}"\nlast open tag is "{last_section}"\nline {_CURRENT_LINE + 1} What it means
Raised by the Mustache tokenizer in `langchain_core.utils.mustache` when a closing section tag `{{/name}}` does not match the most recently opened section. Mustache requires properly nested sections (LIFO), so `{{#a}}...{{/b}}` is rejected; the message names both the tag being closed and the actually-open section. Line numbers are one-based.
Source
Thrown at libs/core/langchain_core/utils/mustache.py:290
# Then check to see if the last opened section
# is the same as us
try:
last_section = open_sections.pop()
except IndexError as e:
msg = (
f'Trying to close tag "{tag_key}"\n'
"Looks like it was not opened.\n"
f"line {_CURRENT_LINE + 1}"
)
raise ChevronError(msg) from e
if tag_key != last_section:
# Otherwise we need to complain
msg = (
f'Trying to close tag "{tag_key}"\n'
f'last open tag is "{last_section}"\n'
f"line {_CURRENT_LINE + 1}"
)
raise ChevronError(msg)
# Do the second check to see if we're a standalone
is_standalone = r_sa_check(template, tag_type, is_standalone)
# Which if we are
if is_standalone:
# Remove the stuff before the newline
template = template.split("\n", 1)[-1]
# Partials need to keep the spaces on their left
if tag_type != "partial":
# But other tags don't
literal = literal.rstrip(" ")
# Start yielding
# Ignore literals that are empty
if literal:
yield ("literal", literal)View on GitHub (pinned to e32fa9a52e)
Solutions
- Reorder the closing tags so they mirror the opening order exactly (innermost closes first).
- Verify exact name matches between `{{#name}}`/`{{^name}}` openers and `{{/name}}` closers — the message tells you the expected name.
- Auto-format/lint Mustache templates in CI to enforce balanced nesting.
Example fix
# before
template = "{{#a}}A{{#b}}B{{/a}}{{/b}}" # closes 'a' while 'b' is open
# after
template = "{{#a}}A{{#b}}B{{/b}}{{/a}}" Defensive patterns
Strategy: validation
Validate before calling
import re
def sections_balanced(template: str) -> bool:
stack = []
for typ, key in re.findall(r"\{\{\s*(#|\^|/)\s*(.*?)\s*\}\}", template):
if typ in "#^":
stack.append(key)
elif not stack or stack.pop() != key:
return False
return not stack
if not sections_balanced(template):
raise ValueError("unbalanced mustache sections") Try / catch
try:
list(tokenize(template))
except ChevronError as e:
# message names the tag and the actually-open section
raise ValueError(f"invalid template: {e}") from e Prevention
- Use the error message: 'last open tag is X' tells you the exact expected closer.
- Avoid hand-nesting deeply; extract partials instead.
- Balance-check templates in CI.
When it happens
Trigger: Interleaved/nested sections closed out of order, e.g. `{{#a}}{{#b}}...{{/a}}{{/b}}`, rendered via `MustachePlaceholderFormatter` or `tokenize`; or opener/closer names that differ by a typo or whitespace.
Common situations: Hand-nested loops/conditionals in prompt templates closed in the wrong order; renaming one of two similar sections (`{{#tool}}` vs `{{#tools}}`) and updating only one side; merging template fragments that break nesting.
Related errors
- Trying to close tag "{tag_key}"\nLooks like it was not opene
- Unexpected EOF\nthe tag "{open_sections[-1]}" was never clos
- Mustache templates cannot be validated.
- unclosed tag at line {_CURRENT_LINE}
- empty tag at line {_CURRENT_LINE}
AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14).
Data as JSON: /api/errors/cf28bd5d4262afa0.
Report an issue: GitHub.