langchain-ai/deepagents · error · ValueError

models can only be provided when agent is a factory

Error message

models can only be provided when agent is a factory

What it means

The model half of a `ModelSpec` is required; `__post_init__` raises `ValueError` when `model` is empty. This guarantees every spec resolves to a concrete model so downstream `create_model` calls never receive a blank model id.

Source

Thrown at libs/acp/deepagents_acp/server.py:260

            models: Optional list of available models with 'value', 'name', and optionally
              'description'
            load_sessions: Advertise and implement durable `session/load`. The agent graph
              must use a checkpointer that survives server restarts.
        """
        super().__init__()
        self._cwd = ""
        self._agent_factory = agent
        self._agent: CompiledStateGraph | None = None
        self._agent_session_id: str | None = None
        self._load_sessions = load_sessions

        if isinstance(agent, CompiledStateGraph):
            if modes is not None:
                msg = "modes can only be provided when agent is a factory"
                raise ValueError(msg)
            if models is not None:
                msg = "models can only be provided when agent is a factory"
                raise ValueError(msg)
            self._modes: SessionModeState | None = None
            self._models: list[dict[str, str]] | None = None
        else:
            self._modes = modes
            self._models = models

        self._session_modes: dict[str, str] = {}
        self._session_mode_states: dict[str, SessionModeState] = {}
        self._session_models: dict[str, str] = {}  # Track current model per session
        self._cancelled = False
        self._session_plans: dict[str, list[dict[str, Any]]] = {}
        self._session_cwds: dict[str, str] = {}
        self._session_mcp_servers: dict[str, list[McpServer]] = {}
        self._allowed_command_types: dict[
            str, set[tuple[str, str | None]]
        ] = {}  # Track allowed command types per session

    def on_connect(self, conn: Client) -> None:

View on GitHub (pinned to a1af029e6e)

Solutions

  1. Supply the model id: `anthropic:claude-sonnet-4-5`, not `anthropic:`
  2. Check the source of the model value (config key, env var) — it is empty or missing
  3. Use `ModelSpec.try_parse(...)` for non-raising validation

Example fix

// before
spec = ModelSpec.parse("anthropic:")
// after
spec = ModelSpec.parse("anthropic:claude-sonnet-4-5")
Defensive patterns

Strategy: validation

Validate before calling

provider, _, model = raw.partition(":")
if not model.strip():
    raise ValueError(f"spec {raw!r} is missing the model id")
spec = ModelSpec(provider=provider, model=model)

Type guard

def is_valid_model_spec(obj: object) -> bool:
    return isinstance(obj, ModelSpec) and bool(obj.provider) and bool(obj.model)

Try / catch

try:
    spec = ModelSpec.parse(raw)
except ValueError as exc:
    logger.error("bad model spec %r: %s", raw, exc)
    spec = DEFAULT_MODEL_SPEC

Prevention

When it happens

Trigger: Calling `ModelSpec(provider='anthropic', model='')`, `ModelSpec.parse('anthropic:')`, or `ModelSpec.parse('anthropic')`... (the latter hits parse's format error; the colon-only case hits this). Any spec string ending at the colon with no model text.

Common situations: Typing `provider:` in a config field with the model name forgotten; a truncated spec after copy/paste; empty value interpolated into a spec template like `f"{provider}:{model}"` where `model` came from missing config.

Related errors


AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29). Data as JSON: /api/errors/eb7b679dbc8c35d9. Report an issue: GitHub.