Skip to content

Template variable escaping with double braces doesn't work as documented #3527

Closed

Description

@j0monty

Description

The ADK documentation states that double braces ({{ and }}) should be used to escape literal curly braces in agent instructions, but the implementation in instructions_utils.py does not properly handle this escaping mechanism.

Expected Behavior

According to the State documentation:

If your instruction text legitimately needs to include literal curly braces (e.g., as part of a code example or JSON snippet), you need to escape them... a common approach is doubling the braces: {{ becomes { and }} becomes }.

When using {{variable_name}} in an instruction, it should render as {variable_name} without attempting template substitution.

Actual Behavior

The regex pattern {+[^{}]*}+ in inject_session_state() matches {{variable_name}} and attempts to substitute it from session state, causing a KeyError when the variable doesn't exist.

The issue is in these lines of google/adk/utils/instructions_utils.py:

Line 124: Regex matches {{variable}}

return await _async_sub(r'{+[^{}]*}+', _replace_match, template)

Lines 82-83: Strips all braces, leaving just 'variable'

async def _replace_match(match) -> str:
var_name = match.group().lstrip('{').rstrip('}').strip()

Line 143: 'variable' passes identifier check

return var_name.isidentifier()

Lines 109-122: Tries to inject from state and fails

if var_name in invocation_context.session.state:
...
else:
raise KeyError(f'Context variable not found: {var_name}.')## Steps to Reproduce

  1. Create an agent with an instruction containing code examples with template literals:
    instruction = """
    Example Python code:
    logger.error(f"User not found: {{user_id}}")

Example TypeScript code:
console.log(User: ${{userId}});
"""2. Run the agent
3. Observe: KeyError: 'Context variable not found: 'user_id'.

Environment

  • ADK Version: 1.18.0 (tested with google-adk>=1.18.0)
  • Python Version: 3.12
  • OS: macOS 24.6.0

Workaround

Use property access (dots) in code examples instead of simple identifiers, since _is_valid_state_name() returns False for non-identifiers:

This works because 'user.id' is not a valid identifier

logger.error(f"User not found: {{user.id}}")## Suggested Fix

The _replace_match function should detect double-brace patterns and return the literal content without attempting substitution:

async def _replace_match(match) -> str:
matched_text = match.group()

# Check if this is an escaped pattern (starts with {{ )
if matched_text.startswith('{{') and matched_text.endswith('}}'):
    # Return with single braces (unescape)
    return matched_text[1:-1]

# Existing logic for template substitution
var_name = matched_text.lstrip('{').rstrip('}').strip()
...Alternatively, update the regex to exclude double-brace patterns from matching, though this is more complex.

Impact

This bug prevents using realistic code examples (especially Python f-strings and TypeScript/JavaScript template literals) in agent instructions, which is critical for code generation and software engineering agents.

Activity

  1. added
    core[Component] This issue is related to the core interface and implementation
    on Nov 13, 2025
  2. added theissue type on Nov 13, 2025
  3. self-assigned this
    on Nov 15, 2025
  4. added
    tools[Component] This issue is related to tools
    on Nov 19, 2025
  5. surajksharma07 commented on Dec 8, 2025

    @surajksharma07
    Collaborator

    @j0monty the double brace escaping is documented but not implemented.

    The fix is straightforward: in _replace_match() (instructions_utils.py:81), add a check before the existing logic: if matched_text.startswith('{{') and matched_text.endswith('}}'): return matched_text[1:-1].

    This will escape {{variable}} to {variable} as documented.

    Currently there's no clean workaround for code examples with simple identifiers like {{name}} - the dot hack {{user.id}} only helps for non-identifiers.

    Thanks!

  6. added
    needs review[Status] The PR/issue is awaiting review from the maintainer
    on Dec 8, 2025
  7. removed
    needs review[Status] The PR/issue is awaiting review from the maintainer
    on Dec 19, 2025
  8. ItsMacto commented on Feb 5, 2026

    @ItsMacto
    Contributor

    Hi, can this be assigned to me?!

  9. added a commit that references this issue on Feb 5, 2026
    093e5e1
  10. surajksharma07 commented on Feb 5, 2026

    @surajksharma07
    Collaborator

    @j0monty PR #4375 (submitted today) addresses this issue.

    The fix hasn't been merged into any release yet (checked v1.23.0).

    Once PR #4375 is merged, upgrade to the next ADK release.

    Until then, use the workaround of adding dots to identifiers (e.g., {{user.id}} instead of {{user_id}}) since non-identifiers are returned as-is.

  11. added a commit that references this issue on Feb 10, 2026
    7c7d25a
  12. added a commit that references this issue on Feb 11, 2026
    079f7a3
  13. added 2 commits that reference this issue on Feb 22, 2026
    b89a3d3
    3043915
  14. added 2 commits that reference this issue on Aug 11, 2026
    2ebd688
    551c2e7
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

core[Component] This issue is related to the core interface and implementationgood first issue[Community] This issue is good for newcomers to participatetools[Component] This issue is related to tools

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions