{"record":{"id":"5b831c3982e441a3","repo":"deepset-ai/haystack","slug":"prompt-must-have-exactly-one-variable-called-docu","errorCode":null,"errorMessage":"Prompt must have exactly one variable called 'document'. Found {','.join(variables) or 'no variables'} in the prompt.","messagePattern":"Prompt must have exactly one variable called 'document'\\. Found (.+?) in the prompt\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"haystack/components/extractors/llm_metadata_extractor.py","lineNumber":191,"sourceCode":"            should pass `{\"response_format\": {\"type\": \"json_object\"}}` in the `generation_kwargs`.\n        :param expected_keys: The keys expected in the JSON output from the LLM.\n        :param page_range: A range of pages to extract metadata from. For example, page_range=['1', '3'] will extract\n            metadata from the first and third pages of each document. It also accepts printable range strings, e.g.:\n            ['1-3', '5', '8', '10-12'] will extract metadata from pages 1, 2, 3, 5, 8, 10,11, 12.\n            If None, metadata will be extracted from the entire document for each document in the documents list.\n            This parameter is optional and can be overridden in the `run` method.\n        :param raise_on_failure: Whether to raise an error on failure during the execution of the Generator or\n            validation of the JSON output.\n        :param max_workers: The maximum number of workers to use in the thread pool executor.\n            This parameter is used limit the maximum number of requests that should be allowed to run concurrently\n            when using the `run_async` method.\n        \"\"\"\n        self.prompt = prompt\n        ast = SandboxedEnvironment().parse(prompt)\n        template_variables = meta.find_undeclared_variables(ast)\n        variables = list(template_variables)\n        if variables != [\"document\"]:\n            raise ValueError(\n                f\"Prompt must have exactly one variable called 'document'. \"\n                f\"Found {','.join(variables) or 'no variables'} in the prompt.\"\n            )\n        self.builder = PromptBuilder(prompt, required_variables=variables)\n        self.raise_on_failure = raise_on_failure\n        self.expected_keys = expected_keys or []\n        self.splitter = DocumentSplitter(split_by=\"page\", split_length=1)\n        self.expanded_range = expand_page_range(page_range) if page_range else None\n        self.max_workers = max_workers\n        self._chat_generator = chat_generator\n\n    def warm_up(self) -> None:\n        \"\"\"\n        Warm up the underlying chat generator and splitter.\n        \"\"\"\n        for inner in (self._chat_generator, self.splitter):\n            if hasattr(inner, \"warm_up\"):\n                inner.warm_up()","sourceCodeStart":173,"sourceCodeEnd":209,"githubUrl":"https://github.com/deepset-ai/haystack/blob/e318778c9bf60a1963e3b5f451359655dd696c30/haystack/components/extractors/llm_metadata_extractor.py#L173-L209","documentation":"LLMMetadataExtractor requires its prompt template to declare exactly one Jinja variable named 'document', into which each document's text is rendered. Any other set of variables (none, extra, or differently named) raises ValueError in __init__.","triggerScenarios":"Constructing LLMMetadataExtractor(prompt=\"Extract metadata from {{ text }}\") or with no variable, or with extra variables like {{ schema }} — the parsed variables list must equal [\"document\"].","commonSituations":"Reusing a prompt from another extractor (e.g. the image extractor that forbids variables); renaming the variable to 'doc' or 'text'; appending additional placeholder variables for custom context.","solutions":["Use exactly the variable name 'document' in the prompt: \"Extract {{ meta }} from {{ document }}\"-style with only {{ document }}","Remove any additional {{ }} placeholders and inline that content directly in the prompt","Keep instructions without placeholders if no templating is needed beyond the document"],"exampleFix":"// before\nextractor = LLMMetadataExtractor(prompt=\"Extract date from {{ text }}\")\n// after\nextractor = LLMMetadataExtractor(prompt=\"Extract the date from {{ document }}\")","handlingStrategy":"validation","validationCode":"from jinja2 import meta, Environment\nvars_ = list(meta.find_undeclared_variables(Environment().parse(prompt)))\nif vars_ != [\"document\"]:\n    raise ValueError(f\"Prompt must use exactly the 'document' variable, found: {vars_}\")","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always reference the document content as {{ document }} in metadata-extractor prompts","Avoid adding extra placeholder variables; inline any static context instead","Test component construction in CI so bad prompts fail before deployment"],"tags":["python","validation","jinja-template"],"backgroundTag":"invalid-template-variables","analyzedSha":"e318778c9bf60a1963e3b5f451359655dd696c30","analyzedAt":"2026-08-30T11:45:20.711Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}