Skip to content

StTemplateRenderer throws runtime exception even with ValidationMode.WARN #5042

@polarbear122

Description

@polarbear122

Spring AI Bug Report: StTemplateRenderer throws runtime exception even with ValidationMode.WARN

Bug description

When using StTemplateRenderer with ValidationMode.WARN, if a template contains variables that are not present in the provided parameter map, the renderer outputs a warning log as expected, but also throws a runtime exception. This causes log pollution and breaks the expected behavior where warnings should only be logged without throwing exceptions.

The issue occurs when calling:

String sysMsg = stTemplateRenderer.apply(promptConfig.getSystemPrompt(), systemMsgParamsMap);

Even though the StTemplateRenderer bean is configured with:

@Bean(name = "stTemplateRenderer")
public StTemplateRenderer stTemplateRenderer() {
    return StTemplateRenderer.builder()
            .validationMode(ValidationMode.WARN)
            .build();
}

When a template variable is missing from the map, two errors are generated:

  1. A warning log (expected): StTemplateRenderer.validate(141) | Not all variables were replaced in the template. Missing variable names are: [currentTimeStr].
  2. A runtime exception (unexpected): StTemplateRenderer.runTimeError(45) | context [anonymous] 36:1 attribute currentTimeStr isn't defined

The runtime exception pollutes the logs and breaks the expected behavior where ValidationMode.WARN should only log warnings without throwing exceptions.

Environment

  • Java Version: OpenJDK 21.0.7 (Microsoft build 21.0.7+6-LTS)
  • Spring AI Version: 1.1.0
  • Template Engine: StringTemplate (StTemplate)

Steps to reproduce

  1. Configure StTemplateRenderer with ValidationMode.WARN:
@Bean(name = "stTemplateRenderer")
public StTemplateRenderer stTemplateRenderer() {
    return StTemplateRenderer.builder()
            .validationMode(ValidationMode.WARN)
            .build();
}
  1. Create a template with a variable that doesn't exist in the parameter map:
String template = "Current time: {currentTimeStr}. User question: {query}";
Map<String, Object> params = Map.of("query", "test question");
// Note: currentTimeStr is missing from params
  1. Apply the template:
String result = stTemplateRenderer.apply(template, params);
  1. Observe the output:
    • Warning log is printed (expected)
    • Runtime exception is thrown (unexpected)

Expected behavior

When ValidationMode.WARN is set, missing template variables should only generate warning logs without throwing runtime exceptions. The renderer should continue processing and replace missing variables with empty strings or leave them as-is, similar to how ValidationMode.NONE behaves, but with warning logs.

Minimal Complete Reproducible example

@Test
public void testStTemplateRendererWithWarnMode() {
    StTemplateRenderer renderer = StTemplateRenderer.builder()
            .validationMode(ValidationMode.WARN)
            .build();
    
    String template = "Current time: {currentTimeStr}. User question: {query}";
    Map<String, Object> params = Map.of("query", "test question");
    // currentTimeStr is intentionally missing
    
    // Expected: Should only log a warning, not throw an exception
    String result = renderer.apply(template, params);
    
    // This assertion may fail if the exception is thrown
    assertNotNull(result);
}

Actual behavior:

  • Warning log is printed: Not all variables were replaced in the template. Missing variable names are: [currentTimeStr].
  • Runtime exception is thrown: context [anonymous] 36:1 attribute currentTimeStr isn't defined
  • Test fails with IllegalStateException or similar runtime exception

Expected behavior:

  • Warning log is printed: Not all variables were replaced in the template. Missing variable names are: [currentTimeStr].
  • No runtime exception is thrown
  • Test passes, and the result contains the template with the missing variable left as-is or replaced with empty string

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions