deepset-ai/haystack · error

required_variables must not be empty. Set it to '*' to requi

Error message

required_variables must not be empty. Set it to '*' to require all variables, or provide a non-empty list of variable names.

What it means

PromptBuilder-style LLM component (llm.py) validates `required_variables` at init: an explicit empty list is ambiguous (require nothing? everything?), so it's rejected. Pass '*' to require all template variables or a non-empty list of variable names.

Source

Thrown at haystack/components/generators/chat/llm.py:83

            Only relevant when `user_prompt` or `system_prompt` contains template variables.
        :param streaming_callback: A callback that will be invoked when a response is streamed from the LLM.
        :raises ValueError: If user_prompt contains template variables but required_variables is an empty list.
        """
        super(LLM, self).__init__(  # noqa: UP008
            chat_generator=chat_generator,
            system_prompt=system_prompt,
            user_prompt=user_prompt,
            required_variables=required_variables,
            streaming_callback=streaming_callback,
        )
        if self._user_chat_prompt_builder is None or len(self._user_chat_prompt_builder.variables) == 0:
            # This means user_prompt is empty or has no template variables.
            # To ensure properly scheduling we then require messages to be passed at runtime.
            component.set_input_type(self, "messages", list[ChatMessage])
        else:
            # user prompt was provided with variables
            if isinstance(required_variables, list) and len(required_variables) == 0:
                raise ValueError(
                    "required_variables must not be empty. Set it to '*' to require all variables, "
                    "or provide a non-empty list of variable names."
                )
            component.set_input_type(self, "messages", list[ChatMessage], None)

        # The Agent base class declares `step_count` and `tool_call_counts` as outputs, but an LLM never has tools
        # and always runs exactly one step — those values are uninformative, so drop them from the public surface.
        # `token_usage` is still meaningful and stays exposed.
        component.set_output_types(
            self, messages=list[ChatMessage], last_message=ChatMessage, token_usage=dict[str, Any]
        )

    def to_dict(self) -> dict[str, Any]:
        """
        Serialize the LLM component to a dictionary.

        :return: Dictionary with serialized data.
        """

View on GitHub (pinned to e318778c9b)

Solutions

  1. Pass required_variables='*' to require all template variables
  2. Pass a non-empty list like required_variables=['question']
  3. If nothing is required, omit the parameter (default None) instead of passing []
  4. Fix the upstream expression producing the empty list

Example fix

// before
llm = _LLMComponent(generator, required_variables=[])
// after
llm = _LLMComponent(generator, required_variables="*")
Defensive patterns

Strategy: validation

Validate before calling

if isinstance(required_variables, list) and len(required_variables) == 0:
    required_variables = "*"  # or omit the argument entirely

Prevention

When it happens

Trigger: `_LLMComponent(..., required_variables=[])` — typically when building the list dynamically and it ends up empty; also triggered when wiring the component for Agent pipelines with an empty list literal.

Common situations: Computing required_variables from user input or config that yielded no items; defaulting to `[]` instead of None/'*'; refactors where variables were removed but the parameter kept as [].

Related errors


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