langchain-ai/langchain · error · ValueError

Can't load chat prompt without template

Error message

Can't load chat prompt without template

What it means

The legacy `chat` prompt loader (`_load_chat_prompt`) expects the config's first message to carry an inline `template` key that it pops to rebuild the prompt via `ChatPromptTemplate.from_template`. If `messages` is empty or the first message's `prompt` dict has no (or empty) `template`, it raises `ValueError: Can't load chat prompt without template`.

Source

Thrown at libs/core/langchain_core/prompts/loading.py:287

        msg = f"Got unsupported file type {file_path.suffix}"
        raise ValueError(msg)
    # Load the prompt from the config now.
    return load_prompt_from_config(config, allow_dangerous_paths=allow_dangerous_paths)


def _load_chat_prompt(
    config: dict[str, Any],
    *,
    allow_dangerous_paths: bool = False,  # noqa: ARG001
) -> ChatPromptTemplate:
    """Load chat prompt from config."""
    messages = config.pop("messages")
    template = messages[0]["prompt"].pop("template") if messages else None
    config.pop("input_variables")

    if not template:
        msg = "Can't load chat prompt without template"
        raise ValueError(msg)

    return ChatPromptTemplate.from_template(template=template, **config)


type_to_loader_dict: dict[str, Callable[..., BasePromptTemplate[str]]] = {
    "prompt": _load_prompt,
    "few_shot": _load_few_shot_prompt,
    "chat": _load_chat_prompt,
}

View on GitHub (pinned to e32fa9a52e)

Solutions

  1. Ensure the first message contains an inline `template` string: `{"messages": [{"prompt": {"template": "Hi {name}"}}]}`.
  2. Prefer modern serialization: `dumpd(chat_prompt)` / `loads(...)` from `langchain_core.load`, which handles arbitrary message structures.
  3. Build chat prompts in code with `ChatPromptTemplate.from_messages([...])` instead of the legacy config format.

Example fix

# before
# {"_type": "chat", "input_variables": [], "messages": []}
load_prompt('chat.json')  # ValueError

# after
# {"_type": "chat", "input_variables": ["name"],
#  "messages": [{"prompt": {"template": "Hi {name}"}}]}
load_prompt('chat.json')
Defensive patterns

Strategy: validation

Validate before calling

msgs = config.get('messages') or []
first = msgs[0].get('prompt', {}) if msgs else {}
if not first.get('template'):
    raise ValueError('chat config needs an inline template in the first message')
load_prompt_from_config(config)

Type guard

def chat_config_has_template(config: dict) -> bool:
    msgs = config.get('messages') or []
    return bool(msgs) and bool((msgs[0] or {}).get('prompt', {}).get('template'))

Prevention

When it happens

Trigger: Loading a `{"_type": "chat"}` config whose `messages` list is `[]`, or whose first message is `{"prompt": {}}` / has a `template_path` instead of inline `template`. Note: a missing `messages` key raises `KeyError` before this check.

Common situations: Serialized chat prompts whose messages used template files; empty-message configs from a failed export; chat configs from other tools that structure messages differently (e.g. tuples or role/content pairs).

Related errors


AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14). Data as JSON: /api/errors/8978bb485b5b16b3. Report an issue: GitHub.