deepset-ai/haystack · error

Prompt must have exactly one variable called 'document'. Fou

Error message

Prompt must have exactly one variable called 'document'. Found {','.join(variables) or 'no variables'} in the prompt.

What it means

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__.

Source

Thrown at haystack/components/extractors/llm_metadata_extractor.py:191

            should pass `{"response_format": {"type": "json_object"}}` in the `generation_kwargs`.
        :param expected_keys: The keys expected in the JSON output from the LLM.
        :param page_range: A range of pages to extract metadata from. For example, page_range=['1', '3'] will extract
            metadata from the first and third pages of each document. It also accepts printable range strings, e.g.:
            ['1-3', '5', '8', '10-12'] will extract metadata from pages 1, 2, 3, 5, 8, 10,11, 12.
            If None, metadata will be extracted from the entire document for each document in the documents list.
            This parameter is optional and can be overridden in the `run` method.
        :param raise_on_failure: Whether to raise an error on failure during the execution of the Generator or
            validation of the JSON output.
        :param max_workers: The maximum number of workers to use in the thread pool executor.
            This parameter is used limit the maximum number of requests that should be allowed to run concurrently
            when using the `run_async` method.
        """
        self.prompt = prompt
        ast = SandboxedEnvironment().parse(prompt)
        template_variables = meta.find_undeclared_variables(ast)
        variables = list(template_variables)
        if variables != ["document"]:
            raise ValueError(
                f"Prompt must have exactly one variable called 'document'. "
                f"Found {','.join(variables) or 'no variables'} in the prompt."
            )
        self.builder = PromptBuilder(prompt, required_variables=variables)
        self.raise_on_failure = raise_on_failure
        self.expected_keys = expected_keys or []
        self.splitter = DocumentSplitter(split_by="page", split_length=1)
        self.expanded_range = expand_page_range(page_range) if page_range else None
        self.max_workers = max_workers
        self._chat_generator = chat_generator

    def warm_up(self) -> None:
        """
        Warm up the underlying chat generator and splitter.
        """
        for inner in (self._chat_generator, self.splitter):
            if hasattr(inner, "warm_up"):
                inner.warm_up()

View on GitHub (pinned to e318778c9b)

Solutions

  1. Use exactly the variable name 'document' in the prompt: "Extract {{ meta }} from {{ document }}"-style with only {{ document }}
  2. Remove any additional {{ }} placeholders and inline that content directly in the prompt
  3. Keep instructions without placeholders if no templating is needed beyond the document

Example fix

// before
extractor = LLMMetadataExtractor(prompt="Extract date from {{ text }}")
// after
extractor = LLMMetadataExtractor(prompt="Extract the date from {{ document }}")
Defensive patterns

Strategy: validation

Validate before calling

from jinja2 import meta, Environment
vars_ = list(meta.find_undeclared_variables(Environment().parse(prompt)))
if vars_ != ["document"]:
    raise ValueError(f"Prompt must use exactly the 'document' variable, found: {vars_}")

Prevention

When it happens

Trigger: Constructing LLMMetadataExtractor(prompt="Extract metadata from {{ text }}") or with no variable, or with extra variables like {{ schema }} — the parsed variables list must equal ["document"].

Common situations: 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.

Related errors


AI-assisted analysis of deepset-ai/haystack@e318778c9b (2026-08-30). Data as JSON: /api/errors/5b831c3982e441a3. Report an issue: GitHub.