langchain-ai/langchain · error · NotImplementedError

Unsupported version: {version!r}. Expected 'v1', 'v2', or 'v

Error message

Unsupported version: {version!r}. Expected 'v1', 'v2', or 'v3'.

What it means

Raised by `Runnable.astream_events` when the `version` argument is anything other than the literals 'v1', 'v2', or 'v3'. The dispatch chain matches those three strings and falls into an `else` branch marked `# type: ignore[unreachable]` (unreachable only from the type-checker's perspective — at runtime arbitrary strings reach it), raising `NotImplementedError` with the offending value echoed via `{version!r}`.

Source

Thrown at libs/core/langchain_core/runnables/base.py:1655

                removal="2.0.0",
            )
            # First implementation, built on top of astream_log API
            # This implementation will be deprecated as of 0.2.0
            event_stream = _astream_events_implementation_v1(
                self,
                input,
                config=config,
                include_names=include_names,
                include_types=include_types,
                include_tags=include_tags,
                exclude_names=exclude_names,
                exclude_types=exclude_types,
                exclude_tags=exclude_tags,
                **kwargs,
            )
        else:
            msg = f"Unsupported version: {version!r}. Expected 'v1', 'v2', or 'v3'."  # type: ignore[unreachable]
            raise NotImplementedError(msg)

        async with aclosing(event_stream):
            async for event in event_stream:
                yield event

    @overload
    def stream_events(
        self,
        input: Any,
        config: RunnableConfig | None = None,
        *,
        version: Literal["v1", "v2"] = "v2",
        include_names: Sequence[str] | None = None,
        include_types: Sequence[str] | None = None,
        include_tags: Sequence[str] | None = None,
        exclude_names: Sequence[str] | None = None,
        exclude_types: Sequence[str] | None = None,
        exclude_tags: Sequence[str] | None = None,

View on GitHub (pinned to e32fa9a52e)

Solutions

  1. Use exactly `"v1"`, `"v2"`, or `"v3"` — current default is `"v2"`
  2. If the version comes from config, validate it once at load: `if version not in {"v1","v2","v3"}: raise ConfigError(...)`
  3. Omit the argument entirely when the default (v2) is acceptable

Example fix

# before
version = os.environ.get("EVENTS_VERSION", "2")
chain.astream_events(inp, version=version)  # NotImplementedError: Unsupported version: '2'

# after
version = os.environ.get("EVENTS_VERSION", "v2")
assert version in {"v1", "v2", "v3"}
chain.astream_events(inp, version=version)
Defensive patterns

Strategy: validation

Validate before calling

EVENT_VERSIONS = {"v1", "v2", "v3"}

def checked_event_version(v: str) -> str:
    if v not in EVENT_VERSIONS:
        msg = f"event version must be one of {sorted(EVENT_VERSIONS)}, got {v!r}"
        raise ValueError(msg)
    return v

Type guard

def is_event_version(v: object) -> bool:
    return isinstance(v, str) and v in {"v1", "v2", "v3"}

Try / catch

try:
    async for ev in chain.astream_events(inp, version=v):
        ...
except NotImplementedError as e:
    if "Unsupported version" in str(e):
        raise ValueError(f"bad event version from config: {v!r}") from e
    raise

Prevention

When it happens

Trigger: `chain.astream_events(inp, version="v4")`, `version="V2"` (capitalized), `version="2"` (missing the v), or a version string read from config without validation. The Literal type protects typed call sites only; untyped strings pass straight through.

Common situations: Version values sourced from environment variables, YAML config, or CLI flags; code written against future/imagined API versions; typos and casing mistakes that static typing does not catch because the call site is untyped.

Related errors


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