langchain-ai/langchain · error · ValueError

RunnableSequence contains conflicting config specsfor {spec_

Error message

RunnableSequence contains conflicting config specsfor {spec_id}: {[first, *others]}

What it means

When collecting `configurable_fields` specs for a `RunnableSequence`, langchain groups specs by `id` and requires all specs sharing an id to be equal. If two steps in the sequence declare a configurable field with the same id but different definitions (different options/annotations), this ValueError is raised. Note the message itself is missing a space ('specsfor') — a cosmetic bug in the f-string.

Source

Thrown at libs/core/langchain_core/runnables/utils.py:708

    Raises:
        ValueError: If the runnable sequence contains conflicting config specs.
    """
    grouped = groupby(
        sorted(specs, key=lambda s: (s.id, *(s.dependencies or []))), lambda s: s.id
    )
    unique: list[ConfigurableFieldSpec] = []
    for spec_id, dupes in grouped:
        first = next(dupes)
        others = list(dupes)
        if len(others) == 0 or all(o == first for o in others):
            unique.append(first)
        else:
            msg = (
                "RunnableSequence contains conflicting config specs"
                f"for {spec_id}: {[first, *others]}"
            )
            raise ValueError(msg)
    return unique


class _RootEventFilter:
    def __init__(
        self,
        *,
        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,
    ) -> None:
        """Utility to filter the root event in the astream_events implementation.

        This is simply binding the arguments to the namespace to make save on
        a bit of typing in the astream_events implementation.

View on GitHub (pinned to e32fa9a52e)

Solutions

  1. Give each field a globally unique id per definition (e.g. 'chat_model' vs 'fallback_model') so no id conflict occurs.
  2. If both steps must share one id, make the `ConfigurableFieldSpec` definitions identical (same options, annotation, default, name).
  3. Inspect `chain.config_schema()` / `chain.configurable_fields()` to see the colliding specs before wiring `.with_config`.

Example fix

# before
llm_a = chat_a.with_configurable_fields(model=ConfigurableField(id='model', options={'gpt': ..., 'gpt4': ...}))
llm_b = chat_b.with_configurable_fields(model=ConfigurableField(id='model', options={'haiku': ..., 'sonnet': ...}))
seq = llm_a | llm_b  # conflicting spec id 'model'
# after
llm_b = chat_b.with_configurable_fields(model=ConfigurableField(id='fallback_model', options={'haiku': ..., 'sonnet': ...}))
seq = llm_a | llm_b
Defensive patterns

Strategy: validation

Validate before calling

from collections import defaultdict

def spec_ids_unique(seq_steps) -> bool:
    seen = defaultdict(list)
    for step in seq_steps:
        for spec in getattr(step, 'config_specs', lambda: [])():
            seen[spec.id].append(spec)
    for sid, specs in seen.items():
        if len({repr(s) for s in specs}) > 1:
            return False  # same id, differing definitions -> will raise
    return True

assert spec_ids_unique(seq.steps)

Try / catch

try:
    final = seq.with_config(configurable={'model': 'gpt'})
except ValueError as e:
    if 'conflicting config specs' in str(e):
        # rename the colliding field id on one step and rebuild
        rebuild_with_unique_ids()
    else:
        raise

Prevention

When it happens

Trigger: Composing a sequence where two runnables each call `ConfigurableField(id='model', ...)` with different `options`, `name`, or `default` values — e.g. building `prompt | llm.with_configurable_fields(model=...) | llm2.with_configurable_fields(model=...)` with mismatched field definitions.

Common situations: Reusing a configurable-field id across two partner models (e.g. an OpenAI and an Anthropic chat both configurable as `model`) inside one sequence; copy-pasting `with_configurable_fields` blocks and editing only one; building `.with_config(configurable={...})` chains after a refactor changed one field's options.

Related errors


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