Problem – RAG Prompt Rendering Failure After Updating Template Placeholders
In a staging deployment of Weaviate (Docker Compose, PostgreSQL vector store, generative AI module v1.22), updating the prompt_template.yaml to replace the built‑in {{question}} placeholder with a custom name (e.g., {{user_query}}) caused the generative endpoint to return HTTP 500. The logs contain errors such as:
Error rendering prompt: KeyError: 'user_query'
InvalidRequestError: Prompt contains unresolved placeholders
TemplateRuntimeError: Undefined variable 'user_query'
Result: the RAG query never reaches the LLM because the prompt sent to the model is malformed.
Root Cause Analysis
Supported placeholder syntax
The official documentation for the Generative AI module states that only the placeholders defined by the module are guaranteed to be substituted: {{question}}, {{context}}, and a few class‑property tokens (Weaviate Generative AI – Prompt templates).
Template versioning and strict Jinja2 mode
Starting with v1.22 the internal Jinja2 engine runs in strict mode. Any variable that is not present in the rendering context raises a TemplateRuntimeError (GitHub issue #2319). This change turned a previously silent omission into a hard failure.
Configuration mismatch
- The environment variable
WEAVIATE_ENABLE_PROMPT_TEMPLATESmust be set totruefor custom files to be loaded (community forum thread). - After the Docker Compose update, the
PROMPT_TEMPLATE_FILEpath still pointed to the old file, causing Weaviate to fall back to the default template where{{question}}is still expected (GitHub issue #2984).
Combined, these factors mean that the new placeholder name is never supplied to the rendering engine, leading to the observed KeyError and InvalidRequestError.
Investigation & Debugging Steps
- Confirm the template file is being read.
docker exec -it weaviate cat /etc/weaviate/prompt_template.yamlExpected output should show the updated placeholders.
- Check environment variables in the running container.
docker exec -it weaviate env | grep -E 'WEAVIATE|PROMPT'Look for:
WEAVIATE_ENABLE_PROMPT_TEMPLATES=true PROMPT_TEMPLATE_FILE=/etc/weaviate/prompt_template.yamlIf the flag is missing or set to
false, the custom file is ignored. - Inspect the rendering context. Enable debug logging for the generative module (add
LOG_LEVEL=DEBUGto the container env) and search for the line:DEBUG generative.rendering: rendering context: {'question': '…', 'context': '…'}If
user_queryis absent, the placeholder will fail. - Validate Jinja2 strict mode behavior. Reproduce the error with a minimal template:
template: "Answer: {{user_query}}"Run a curl request:
curl -X POST http://localhost:8080/v1/generate \ -H "Content-Type: application/json" \ -d '{"question":"What is Weaviate?"}'Observe the same
TemplateRuntimeError. - Check for stale template cache. Restart the Weaviate container to force a cache refresh:
docker compose restart weaviateIf the error disappears after restart, a race condition was caching the old template (issue #2984).
Resolution – Align Placeholder Names and Configuration
Option 1 – Use Built‑in Placeholders
Revert the template to the supported {{question}} placeholder.
# before (broken)
prompt: |
Answer the following question using the context:
{{context}}
Question: {{user_query}}
# after (working)
prompt: |
Answer the following question using the context:
{{context}}
Question: {{question}}
Why it works: The rendering engine always provides question and context variables, so no KeyError occurs.
Option 2 – Extend the Rendering Context
If a custom name is required, expose it via the additionalProperties field in the query payload and map it in the module configuration.
# prompt_template.yaml (custom placeholder)
prompt: |
Answer using the provided context:
{{context}}
Query: {{user_query}}
# weaviate.yaml (module config)
generative:
enabled: true
promptTemplateFile: /etc/weaviate/prompt_template.yaml
additionalVariables:
- name: user_query
source: request.question
After adding additionalVariables, restart the container.
Update Docker Compose
# docker-compose.yml snippet
services:
weaviate:
image: semitechnologies/weaviate:1.22.0
environment:
- WEAVIATE_ENABLE_PROMPT_TEMPLATES=true
- PROMPT_TEMPLATE_FILE=/etc/weaviate/prompt_template.yaml
- LOG_LEVEL=DEBUG
volumes:
- ./prompt_template.yaml:/etc/weaviate/prompt_template.yaml:ro
Restart:
docker compose up -d weaviate
Verification – Confirm Prompt Renders Correctly
- Send a RAG request:
curl -X POST http://localhost:8080/v1/generate \ -H "Content-Type: application/json" \ -d '{"question":"Explain vector search"}' - Inspect the response payload. The
promptfield (if logged) should contain the substituted values, e.g.:{ "result": "Vector search allows..." } - Check the Weaviate logs for the absence of rendering errors:
2026-08-31T12:34:56Z INFO generative.rendering: rendered prompt successfully - Optionally, enable the
WEAVIATE_PROMPT_RENDER_DEBUG=trueflag to log the final prompt string for audit.
Prevention – Guardrails for Future Template Changes
- Validate template syntax before deployment. Use a local Jinja2 linter:
python -c "import jinja2, sys; jinja2.Environment(undefined=jinja2.StrictUndefined).from_string(open('prompt_template.yaml').read())" - Automate placeholder verification. In CI, run a smoke test that sends a dummy query and asserts that the response does not contain raw
{{.*}}tokens. - Pin the generative module version. Avoid unexpected strict‑mode switches by specifying the exact Weaviate image tag.
- Keep
WEAVIATE_ENABLE_PROMPT_TEMPLATESenabled. Document this requirement in the deployment README. - Version the template file. Include a
template_versionfield (as recommended in the docs) and bump it on every change; the module will reject stale caches if the version mismatches.
FAQ – Common Follow‑Up Questions
- Why does the error appear only after upgrading to v1.22?
Because v1.22 enables Jinja2 strict mode, turning missing variables into hard failures (issue #2319). - Can I use arbitrary placeholder names like
{{my_input}}?
Only if you declare them in the module’sadditionalVariablesmapping. Otherwise the engine will raiseKeyErrororTemplateRuntimeError. - How do I know which variables are available for substitution?
The documentation lists the built‑in variables (question,context, class properties). Runtime logs atDEBUGlevel also print the rendering context. - What does “InvalidRequestError: Prompt contains unresolved placeholders” mean?
It indicates that after rendering, the prompt string still contains{{…}}tokens, meaning at least one placeholder was not supplied. - Is there a way to fallback to a default value when a variable is missing?
Yes. Use Jinja2’s default filter in the template, e.g.,{{user_query | default('') }}. This works only when strict mode is disabled or the variable is optional.
Related Topic Hub: Vector Databases Troubleshooting Hub