{"record":{"id":"58f85ad656622662","repo":"langchain-ai/deepagents","slug":"modes-can-only-be-provided-when-agent-is-a-factory","errorCode":null,"errorMessage":"modes can only be provided when agent is a factory","messagePattern":"modes can only be provided when agent is a factory","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"libs/acp/deepagents_acp/server.py","lineNumber":257,"sourceCode":"        Args:\n            agent: Either a compiled state graph or a factory function that creates one\n            modes: Optional mode configuration (deprecated, use config_options instead)\n            models: Optional list of available models with 'value', 'name', and optionally\n              'description'\n            load_sessions: Advertise and implement durable `session/load`. The agent graph\n              must use a checkpointer that survives server restarts.\n        \"\"\"\n        super().__init__()\n        self._cwd = \"\"\n        self._agent_factory = agent\n        self._agent: CompiledStateGraph | None = None\n        self._agent_session_id: str | None = None\n        self._load_sessions = load_sessions\n\n        if isinstance(agent, CompiledStateGraph):\n            if modes is not None:\n                msg = \"modes can only be provided when agent is a factory\"\n                raise ValueError(msg)\n            if models is not None:\n                msg = \"models can only be provided when agent is a factory\"\n                raise ValueError(msg)\n            self._modes: SessionModeState | None = None\n            self._models: list[dict[str, str]] | None = None\n        else:\n            self._modes = modes\n            self._models = models\n\n        self._session_modes: dict[str, str] = {}\n        self._session_mode_states: dict[str, SessionModeState] = {}\n        self._session_models: dict[str, str] = {}  # Track current model per session\n        self._cancelled = False\n        self._session_plans: dict[str, list[dict[str, Any]]] = {}\n        self._session_cwds: dict[str, str] = {}\n        self._session_mcp_servers: dict[str, list[McpServer]] = {}\n        self._allowed_command_types: dict[\n            str, set[tuple[str, str | None]]","sourceCodeStart":239,"sourceCodeEnd":275,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/acp/deepagents_acp/server.py#L239-L275","documentation":"`ModelSpec` validates itself in `__post_init__`: a spec must name both a provider and a model. This error means a `ModelSpec` was constructed with an empty `provider` string (e.g. `ModelSpec(provider='', model='claude-sonnet-4-5')` or `ModelSpec.parse(':model')`... actually `:model` yields provider `''`). The library throws it early so an unusable spec never reaches model construction.","triggerScenarios":"Calling `ModelSpec(provider='', model=...)`, `ModelSpec.parse(':gpt-5')`, or `ModelSpec.parse('')` — a spec string whose text before the first colon is empty. Also reachable when callers build specs by slicing a `provider:model` string at a wrong separator.","commonSituations":"Hand-editing `[models]` config keys with `:model` instead of `provider:model`; programmatic spec construction where the provider variable is empty because detection (`detect_provider`) failed or an env var was blank; string splitting on the wrong delimiter.","solutions":["Include the provider prefix: use `anthropic:claude-sonnet-4-5`, not just the model id","If constructing programmatically, check the provider is non-empty before building the `ModelSpec`","Use `ModelSpec.try_parse(...)` and handle `None` instead of letting it raise"],"exampleFix":"// before\nspec = ModelSpec.parse(\":claude-sonnet-4-5\")\n// after\nspec = ModelSpec.parse(\"anthropic:claude-sonnet-4-5\")","handlingStrategy":"validation","validationCode":"def has_provider(spec: str) -> bool:\n    return bool(spec) and bool(spec.split(\":\", 1)[0].strip())\n\nif not has_provider(raw):\n    raise ValueError(f\"spec {raw!r} is missing the provider prefix\")\nspec = ModelSpec.parse(raw)","typeGuard":"def is_valid_model_spec(obj: object) -> bool:\n    return isinstance(obj, ModelSpec) and bool(obj.provider) and bool(obj.model)","tryCatchPattern":"try:\n    spec = ModelSpec.parse(raw)\nexcept ValueError as exc:\n    logger.error(\"bad model spec %r: %s\", raw, exc)\n    spec = ModelSpec.parse(f\"anthropic:{raw}\")  # or a sane default","preventionTips":["Always build specs from the `provider:model` string form rather than hand-assembling fields","Validate provider detection results for emptiness before constructing a `ModelSpec`","Prefer `ModelSpec.try_parse` when input is user-supplied"],"tags":["python","validation","model-spec","config"],"backgroundTag":"invalid-model-spec","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}