Skip to content

fix(sdk-python): keep closing brace of nested JSON in get_langchain_prompt - #1920

Open
aniketkrs wants to merge 2 commits into
langfuse:mainfrom
aniketkrs:fix/escape-json-closing-brace
Open

aniketkrs wants to merge 2 commits into
langfuse:mainfrom
aniketkrs:fix/escape-json-closing-brace

Conversation

@aniketkrs

@aniketkrs aniketkrs commented Oct 2, 2026 •

Copy link
Copy Markdown

Fixes langfuse/langfuse#18131.

User impact: prompts containing compact nested JSON (e.g. Example: {"a": {"b": 1}}) render malformed through get_langchain_prompt() — the closing brace of each nesting level is silently dropped ({"a": {"b": 1} instead of {"a": {"b": 1}}), breaking downstream LangChain templates.

Technical cause: in BasePromptClient._escape_json_for_langchain (langfuse/model.py), the closing-brace branch treats every adjacent }} as a pre-escaped pair and leaves it untouched — it never consults the stack, so the stack entry pushed when the JSON { was doubled is never popped and the escaped }} for that brace is never emitted. Each }} run in deeper nesting loses one more brace.

Fix: when a }} pair is seen, pop the stack: if the top entry is a doubled JSON { (True), emit its escaped }} and reprocess the second } so it can close the next brace. Pre-escaped {{ pairs push a None marker so their own }} is still left untouched (verified: {"name": "{{name}}"} still renders correctly).

Verification:

  • Issue repro before the fix: escaped 'Example: {{"a": {{"b": 1}}' renders {"a": {"b": 1} (malformed). After: escaped 'Example: {{"a": {{"b": 1}}}}' renders the original exactly.
  • Differential fuzz over 8000 random brace/JSON/placeholder inputs: every behavior change is an instance of this bug class; no other input shape changed.
  • Added two regression tests in tests/unit/test_prompt_compilation.py (test_compact_nested_json_keeps_closing_braces, test_pre_escaped_placeholder_inside_nested_json), both passing against the fixed code via the real TextPromptClient + PromptTemplate.

RetriggerConfidence Score: 4/5

The PR should not merge until literal }} inside a JSON string no longer produces an invalid LangChain template.

Summary

The PR changes brace-stack handling to preserve closing braces in compact nested JSON and adds two prompt-compilation tests.

  • Adjacent JSON closes are reprocessed individually; pre-escaped opening pairs now receive stack markers.
  • A literal closing-brace pair inside a JSON string can be mistaken for a structural close.

Reviews (1) · Last reviewed commit: "test(sdk-python): regression tests for n..."

Copilot AI balanced review requested due to automatic review settings October 2, 2026 04:02

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

Comment thread langfuse/model.py
Comment on lines +223 to +229
top = stack.pop() if stack else False
if top is True:
# First "}" closes the doubled JSON brace: emit its
# escaped pair, then reprocess the second "}".
out.append("}}")
i += 1
continue

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Literal braces close JSON early When a JSON string value contains literal }}, as in {"regex": "}}"}, this branch treats those characters as the object's closing braces. It adds a third brace inside the string and leaves the actual object close unescaped, so get_langchain_prompt() returns an invalid LangChain template.

Prompt To Fix With AI
This is a comment left during a code review.
Path: langfuse/model.py
Line: 223-229

Comment:
**Literal braces close JSON early** When a JSON string value contains literal `}}`, as in `{"regex": "}}"}`, this branch treats those characters as the object's closing braces. It adds a third brace inside the string and leaves the actual object close unescaped, so `get_langchain_prompt()` returns an invalid LangChain template.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(sdk-python): get_langchain_prompt drops the closing brace of nested JSON

3 participants