{"record":{"id":"e8ce9a5415494332","repo":"langchain-ai/deepagents","slug":"plugin-id-self-plugin-id-r-does-not-match-expec","errorCode":null,"errorMessage":"Plugin id {self.plugin_id!r} does not match {expected!r}","messagePattern":"Plugin id (.+?) does not match (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"libs/code/deepagents_code/plugins/models.py","lineNumber":129,"sourceCode":"    plugin_id: str\n    name: str\n    marketplace: str\n    version: str | None\n    root: Path\n    data_dir: Path\n    manifest: PluginManifest | None\n    inventory: ComponentInventory\n\n    def __post_init__(self) -> None:\n        \"\"\"Validate the canonical plugin identity.\n\n        Raises:\n            ValueError: If `plugin_id` disagrees with `name` and `marketplace`.\n        \"\"\"\n        expected = f\"{self.name}@{self.marketplace}\"\n        if self.plugin_id != expected:\n            msg = f\"Plugin id {self.plugin_id!r} does not match {expected!r}\"\n            raise ValueError(msg)\n\n\n@dataclass(frozen=True, slots=True, kw_only=True)\nclass LocalPluginSource:\n    \"\"\"A plugin stored relative to its marketplace.\"\"\"\n\n    source_type: Literal[\"local\"]\n    path: str\n\n\n@dataclass(frozen=True, slots=True, kw_only=True)\nclass GithubPluginSource:\n    \"\"\"A plugin sourced from a GitHub repository.\"\"\"\n\n    source_type: Literal[\"github\"]\n    repo: str\n    ref: str | None = None\n    path: str | None = None","sourceCodeStart":111,"sourceCodeEnd":147,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/code/deepagents_code/plugins/models.py#L111-L147","documentation":"Plugin dataclass instances enforce the invariant plugin_id == f\"{name}@{marketplace}\" in __post_init__. Constructing a Plugin whose id string disagrees with its name and marketplace fields raises ValueError, because derived caches and lookups (split_plugin_id) rely on the canonical id format.","triggerScenarios":"Constructing Plugin(name='a', marketplace='m', plugin_id='a@other') or passing plugin_id=None/wrong separator while name/marketplace imply a different id; deserializing a plugin record written by an older format.","commonSituations":"Hand-building Plugin objects in tests or scripts with inconsistent fields; migrating state files where marketplace was renamed but cached plugin_id was not; forgetting '@' in a manually composed plugin_id.","solutions":["Set plugin_id to exactly f'{name}@{marketplace}' or omit it if the constructor derives it.","Rename the marketplace in both the marketplace config and plugin_id together.","Fix the source record (state/cache) so its stored id matches name@marketplace."],"exampleFix":"// before\nPlugin(name='lint', marketplace='team', plugin_id='lint@other')\n// after\nPlugin(name='lint', marketplace='team', plugin_id='lint@team')","handlingStrategy":"validation","validationCode":"def build_plugin_id(name: str, marketplace: str) -> str:\n    pid = f\"{name}@{marketplace}\"\n    assert pid == f\"{name}@{marketplace}\"\n    return pid\n\n# construct via helper so id and fields can never drift","typeGuard":"def id_matches(pid: str, name: str, marketplace: str) -> bool:\n    return pid == f\"{name}@{marketplace}\"","tryCatchPattern":"try:\n    plugin = Plugin(**fields)\nexcept ValueError as exc:\n    if \"does not match\" in str(exc):\n        fields[\"plugin_id\"] = f\"{fields['name']}@{fields['marketplace']}\"\n        plugin = Plugin(**fields)","preventionTips":["Always derive plugin_id from name and marketplace with an f-string; never hardcode it.","When renaming a marketplace, rewrite plugin_id wherever it is persisted.","Add a unit test asserting the invariant for every Plugin you construct."],"tags":["validation","dataclass","plugin-id","invariant"],"backgroundTag":"id-format-mismatch","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}