langchain-ai/langchain · error · ValueError

Invalid image template

Error message

Invalid image template: {tmpl}

What it means

In the image-template branch of from_messages/from_template, an image entry whose value is neither str nor dict is rejected with ValueError('Invalid image template'). The branch's type analysis marks this code unreachable (# type: ignore[unreachable]) because the outer isinstance(tmpl, tuple) dispatch should constrain the shape, so hitting it means the dispatch contract was violated (e.g. via unusual subclasses or mutated input).

Solutions

  1. Make every image entry either a format string or a dict with keys among 'url', 'path', 'detail'
  2. Validate assembled template lists before passing them to from_messages: assert each payload is str or dict

Example fix

# before
("human", [{"type": "image_url", "image_url": image_bytes}])  # ValueError

# after
("human", [{"type": "image_url", "image_url": {"url": build_url(image_bytes)}}])
Defensive patterns

Strategy: type-guard

Validate before calling

def valid_image_entry(entry) -> bool:
    t = entry.get("image_url") if isinstance(entry, dict) else entry
    return isinstance(t, (str, dict))

Type guard

def is_image_template(t) -> bool:
    return isinstance(t, (str, dict))

Prevention

When it happens

Trigger: Supplying an image message element whose payload is an int, None, bytes, or an object that str/dict checks fail on, typically through dynamically assembled template lists that bypass static typing.

Common situations: Programmatic prompt builders that splice user/config data into message tuples without validating shape; serialization round-trips that turn a dict into something else.

Related errors


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

Appendix: source

Thrown at libs/core/langchain_core/prompts/chat.py:514

                            template_format=template_format,
                        )
                    elif isinstance(img_template, dict):
                        img_template = dict(img_template)
                        for key in ["url", "path", "detail"]:
                            if key in img_template:
                                input_variables.extend(
                                    get_template_variables(
                                        img_template[key], template_format
                                    )
                                )
                        img_template_obj = ImagePromptTemplate(
                            input_variables=input_variables,
                            template=img_template,
                            template_format=template_format,
                        )
                    else:
                        msg = f"Invalid image template: {tmpl}"  # type: ignore[unreachable]
                        raise ValueError(msg)
                    prompt.append(img_template_obj)
                elif isinstance(tmpl, dict):
                    if template_format == "jinja2":
                        msg = (
                            "jinja2 is unsafe and is not supported for templates "
                            "expressed as dicts. Please use 'f-string' or 'mustache' "
                            "format."
                        )
                        raise ValueError(msg)
                    data_template_obj = DictPromptTemplate(
                        template=cast("dict[str, Any]", tmpl),
                        template_format=template_format,
                    )
                    prompt.append(data_template_obj)
                else:
                    msg = f"Invalid template: {tmpl}"  # type: ignore[unreachable]
                    raise ValueError(msg)
            return cls(prompt=prompt, **kwargs)

View on GitHub (pinned to e32fa9a52e)