{"record":{"id":"fc6d9a495986bf0f","repo":"spring-projects/spring-ai","slug":"not-all-variables-were-replaced-in-the-template-m","errorCode":null,"errorMessage":"Not all variables were replaced in the template. Missing variable names are: %s.","messagePattern":"Not all variables were replaced in the template\\. Missing variable names are: (.+?)\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"spring-ai-template-st/src/main/java/org/springframework/ai/template/st/StTemplateRenderer.java","lineNumber":145,"sourceCode":"\t/**\n\t * Validates that all required template variables are provided in the model. Returns\n\t * the set of missing variables for further handling or logging.\n\t * @param st the StringTemplate instance\n\t * @param templateVariables the provided variables\n\t * @return set of missing variable names, or empty set if none are missing\n\t */\n\tprivate Set<String> validate(ST st, Map<String, ? extends @Nullable Object> templateVariables) {\n\t\tSet<String> templateTokens = getInputVariables(st);\n\t\tSet<String> modelKeys = templateVariables.keySet();\n\t\tSet<String> missingVariables = new HashSet<>(templateTokens);\n\t\tmissingVariables.removeAll(modelKeys);\n\n\t\tif (!missingVariables.isEmpty()) {\n\t\t\tif (this.validationMode == ValidationMode.WARN) {\n\t\t\t\tlogger.warn(VALIDATION_MESSAGE.formatted(missingVariables));\n\t\t\t}\n\t\t\telse if (this.validationMode == ValidationMode.THROW) {\n\t\t\t\tthrow new IllegalStateException(VALIDATION_MESSAGE.formatted(missingVariables));\n\t\t\t}\n\t\t}\n\t\treturn missingVariables;\n\t}\n\n\tprivate Set<String> getInputVariables(ST st) {\n\t\tTokenStream tokens = st.impl.tokens;\n\t\tSet<String> inputVariables = new HashSet<>();\n\t\tboolean isInsideList = false;\n\n\t\tfor (int i = 0; i < tokens.size(); i++) {\n\t\t\tToken token = tokens.get(i);\n\n\t\t\t// Handle list variables with option (e.g., {items; separator=\", \"})\n\t\t\tif (token.getType() == STLexer.LDELIM && i + 1 < tokens.size()\n\t\t\t\t\t&& tokens.get(i + 1).getType() == STLexer.ID) {\n\t\t\t\tif (i + 2 < tokens.size() && tokens.get(i + 2).getType() == STLexer.COLON) {\n\t\t\t\t\tString text = tokens.get(i + 1).getText();","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/spring-ai-template-st/src/main/java/org/springframework/ai/template/st/StTemplateRenderer.java#L127-L163","documentation":"StTemplateRenderer.validate() checks that every variable referenced by the StringTemplate (ST) template is supplied in the options map. When variables are still missing after validation, and the renderer's validationMode is ValidationMode.THROW, it throws this IllegalStateException naming the missing variables. This guards against silently rendering a template with unfilled placeholders.","triggerScenarios":"Calling StTemplateRenderer.create(...) or apply() with a template that references variables (e.g. {prompt}) but passing an options map lacking those keys; also triggered when variable names are misspelled or when ST4 reserved syntax requires variables the caller did not provide.","commonSituations":"Developers switching prompt templates between renderers: STOP-based templates use {var} while ST4 templates need {var;options}, or prompts copied from examples that reference variables like {documents} never populated in the PromptTemplate options; typos between placeholder names and options keys.","solutions":["Add the missing variables (listed in the exception message) to the options Map passed to the renderer/template.","Fix misspellings so option keys exactly match the variable names in the template.","If intentional partial rendering is desired, set the renderer's validationMode to ValidationMode.WARN (or OFF if available) instead of THROW.","Prefer validationMode.THROW in production and pre-render template variable extraction (getInputVariables) to align options with template variables."],"exampleFix":"// before\nMap.of(\"topic\", \"ai\") with template \"Explain {topic} to {audience}\"\n// throws IllegalStateException\n// after\nMap.of(\"topic\", \"ai\", \"audience\", \"developers\")","handlingStrategy":"validation","validationCode":"// Java: validate before rendering\nSet<String> inputVars = templateRenderer.getInputVariables(templateString); // or extract via ST\nSet<String> provided = options.keySet();\nSet<String> missing = new HashSet<>(inputVars); missing.removeAll(provided);\nif (!missing.isEmpty()) throw new IllegalArgumentException(\"Missing template variables: \" + missing);","typeGuard":null,"tryCatchPattern":"// catch IllegalStateException from create/apply\ntry {\n    Prompt prompt = templateRenderer.create(new PromptTemplateOptions(template, options));\n} catch (IllegalStateException e) {\n    logger.warn(\"Template validation failed: {}\", e.getMessage());\n    // fall back to a default template or surface a 400 to the caller\n}","preventionTips":["Keep option keys and template placeholders derived from a single constant source.","Use getTemplateFormat/getInputVariables to diff template variables against options in tests.","Set ValidationMode.THROW in CI to catch template/option mismatches early."],"tags":["template","stringtemplate","validation","illegal-state"],"backgroundTag":"missing-required-argument","analyzedSha":"98a7beda4f29d80a71c5837eb4053b03a93a46f7","analyzedAt":"2026-09-11T14:15:49.441Z","contentChangedAt":"2026-09-11T14:15:49.441Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}