{"record":{"id":"d3a47a83709fa2e3","repo":"langchain-ai/langchain","slug":"unclosed-set-delimiter-tag-nat-line-current-line","errorCode":null,"errorMessage":"unclosed set delimiter tag\\nat line {_CURRENT_LINE}","messagePattern":"unclosed set delimiter tag\\\\nat line (.+?)","errorType":"exception","errorClass":"ChevronError","httpStatus":null,"severity":"error","filePath":"libs/core/langchain_core/utils/mustache.py","lineNumber":175,"sourceCode":"    tag_type = tag_types.get(tag[0], \"variable\")\n\n    # If the type is not a variable\n    if tag_type != \"variable\":\n        # Then that first character is not needed\n        tag = tag[1:]\n\n    # If we might be a set delimiter tag\n    if tag_type == \"set delimiter?\":\n        # Double check to make sure we are\n        if tag.endswith(\"=\"):\n            tag_type = \"set delimiter\"\n            # Remove the equal sign\n            tag = tag[:-1]\n\n        # Otherwise we should complain\n        else:\n            msg = f\"unclosed set delimiter tag\\nat line {_CURRENT_LINE}\"\n            raise ChevronError(msg)\n\n    elif (\n        # If we might be a no html escape tag\n        tag_type == \"no escape?\"\n        # And we have a third curly brace\n        # (And are using curly braces as delimiters)\n        and l_del == \"{{\"\n        and r_del == \"}}\"\n        and template.startswith(\"}\")\n    ):\n        # Then we are a no html escape tag\n        template = template[1:]\n        tag_type = \"no escape\"\n\n    # Strip the whitespace off the key and return\n    return ((tag_type, tag.strip()), template)\n\n","sourceCodeStart":157,"sourceCodeEnd":193,"githubUrl":"https://github.com/langchain-ai/langchain/blob/e32fa9a52eab3b61ad7a45399bfde59b3e580fc4/libs/core/langchain_core/utils/mustache.py#L157-L193","documentation":"Raised by the Mustache tokenizer in `langchain_core.utils.mustache` for a malformed set-delimiter tag. A tag starting with `=` (e.g. `{{= ... }}`) must end with `=` before the closing delimiter — `{{=<% %>=}}` — to switch delimiters. If the trailing `=` is missing, the tag is ambiguous and rejected. The message includes the line number.","triggerScenarios":"A template containing `{{=<% %>}}` (forgot the closing `=`), or any tag whose first character is `=` but which does not end with `=`. Encountered when rendering via `MustachePlaceholderFormatter`/`tokenize`.","commonSituations":"Manually changing delimiters to embed literal `{{ }}` content (JSON, LaTeX) and mistyping the syntax; copying the set-delimiter idiom from docs with a typo; templates authored for a different Mustache dialect.","solutions":["Fix the tag to the exact form `{{=<new> <new>=}}` (leading `=`, space-separated new delimiters, trailing `=`).","If you did not intend to change delimiters, escape or remove the leading `=` inside the tag.","Tokenize templates once at startup to catch delimiter errors early."],"exampleFix":"# before\ntemplate = \"{{=<% %>}}\\nHi <%name%>\"  # missing trailing '='\n\n# after\ntemplate = \"{{=<% %>=}}\\nHi <%name%>\"","handlingStrategy":"validation","validationCode":"import re\n\ndef valid_set_delimiters(template: str) -> bool:\n    # every set-delimiter tag must look like {{= X Y =}}\n    for m in re.finditer(r\"\\{\\{=[^}]*\\}\\}\", template):\n        if not re.fullmatch(r\"\\{\\{=\\s*\\S+\\s+\\S+\\s*=\\}\\}\", m.group(0)):\n            return False\n    return True","typeGuard":null,"tryCatchPattern":"try:\n    list(tokenize(template))\nexcept ChevronError as e:\n    raise ValueError(f\"invalid template: {e}\") from e","preventionTips":["Copy the set-delimiter idiom verbatim: {{=<new> <new>=}}.","Tokenize templates in CI/startup."],"tags":["mustache","delimiters","prompt-template"],"backgroundTag":null,"analyzedSha":"e32fa9a52eab3b61ad7a45399bfde59b3e580fc4","analyzedAt":"2026-08-14T18:42:09.092Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}