{"record":{"id":"2e303f2f9a95c98e","repo":"langchain-ai/deepagents","slug":"a-provider-already-serves-rank-provider-rank","errorCode":null,"errorMessage":"a provider already serves rank {provider.rank}","messagePattern":"a provider already serves rank (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"libs/code/deepagents_code/configuration/resolver.py","lineNumber":356,"sourceCode":"\n        Used for the CLI tier, which exists only after `argparse` runs — long\n        after this resolver may have been built and cached. Unlike\n        `reload_with_replacements`, this advances no generation and touches no\n        files: the CLI provider is in-memory, so there is nothing to reload,\n        and re-arming source diagnostics for an install that invalidates no\n        snapshot would only risk a duplicate warning on the next resolution.\n\n        Args:\n            provider: Provider to insert. Its rank must not already be present.\n\n        Raises:\n            ValueError: If a provider already serves the new provider's rank.\n        \"\"\"\n        with self._lock:\n            ranks = {existing.rank for existing in self._providers}\n            if provider.rank in ranks:\n                msg = f\"a provider already serves rank {provider.rank}\"\n                raise ValueError(msg)\n            self._providers = tuple(\n                sorted((*self._providers, provider), key=lambda p: p.rank)\n            )\n\n    def toml_snapshot(self, rank: int) -> TomlSnapshot | None:\n        \"\"\"Return the cached TOML snapshot at `rank`, if that provider is one.\n\n        Lets a caller build a one-off resolver against the same file\n        generation this resolver is serving -- for example, re-resolving an\n        option with the managed tier masked while keeping the shared user\n        snapshot instead of re-parsing `config.toml` off disk.\n\n        Propagates the `RuntimeError` `current_snapshot` raises when the\n        provider at `rank` produced no snapshot.\n\n        Args:\n            rank: Precedence rank whose snapshot to return.\n","sourceCodeStart":338,"sourceCodeEnd":374,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/code/deepagents_code/configuration/resolver.py#L338-L374","documentation":"ConfigResolver.install_provider enforces that every ConfigProvider occupies a unique rank in the tier ordering. Installing a provider whose `rank` is already claimed by an existing provider raises ValueError rather than silently replacing or shuffling the existing tier, so resolution precedence stays deterministic.","triggerScenarios":"Calling `resolver.install_provider(provider)` (directly or via the public helpers `_resolver_with_reload_overrides` / `install_cli_provider`) when `provider.rank` equals the rank of any provider already registered — e.g. installing a second TOML provider at MANAGED_RANK or a second CLI provider at CLI_RANK on one resolver.","commonSituations":"Test setup installing two fixtures at the same rank; double-initialization installing a CLI provider twice into the same resolver; plugin/config code constructing replacement providers without reusing the replacement API (`reload_with_replacements`) intended for rank reuse.","solutions":["Pick an unused rank for the new provider before installing.","To replace an existing tier, use `resolver.reload_with_replacements({rank: new_provider})` instead of install_provider.","If a CLI provider already exists, reuse the cached resolver instead of installing again (get_config_resolver handles caching)."],"exampleFix":"// before\nresolver.install_provider(TomlFileProvider(name=\"x\", path=p, rank=MANAGED_RANK))\n// ValueError: a provider already serves rank MANAGED_RANK\n// after: replace the tier instead of adding\nresolver.reload_with_replacements({MANAGED_RANK: new_provider})","handlingStrategy":"validation","validationCode":"def can_install(resolver, provider) -> bool:\n    return provider.rank not in {p.rank for p in resolver._providers}\n\nif not can_install(resolver, new_provider):\n    resolver.reload_with_replacements({new_provider.rank: new_provider})\nelse:\n    resolver.install_provider(new_provider)","typeGuard":null,"tryCatchPattern":"try:\n    resolver.install_provider(provider)\nexcept ValueError as exc:\n    if \"already serves rank\" in str(exc):\n        resolver.reload_with_replacements({provider.rank: provider})  # replace, don't add\n    else:\n        raise","preventionTips":["Treat ranks as a fixed tier registry: one provider per rank, constants like MANAGED_RANK/CLI_RANK are taken.","Use reload_with_replacements for any replacement; reserve install_provider for genuinely new tiers.","In tests, allocate unique ranks per fixture or rebuild the resolver between cases."],"tags":["configuration","resolver","rank-conflict","api-misuse"],"backgroundTag":"duplicate-registration-conflict","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}