{"record":{"id":"6d0b79a1c8078aa1","repo":"langchain-ai/deepagents","slug":"provided-snapshot-id-does-not-match-canonical-conf","errorCode":null,"errorMessage":"Provided snapshot_id does not match canonical configuration","messagePattern":"Provided snapshot_id does not match canonical configuration","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"libs/code/deepagents_code/hooks/snapshot.py","lineNumber":106,"sourceCode":"\n        Args:\n            config: Validated Hooks v2 configuration.\n            groups: Matcher groups with source provenance. Plain configurations\n                use a source with no environment overlay.\n            diagnostics: Diagnostics retained from configuration loading.\n            snapshot_id: Optional precomputed canonical hash. When omitted, it\n                is derived from `config`.\n\n        Returns:\n            A snapshot whose handler order, matchers, and id cannot change.\n\n        Raises:\n            ValueError: If `snapshot_id` disagrees with the canonical config.\n        \"\"\"\n        canonical_id = compute_snapshot_id(config, groups=groups)\n        if snapshot_id is not None and snapshot_id != canonical_id:\n            msg = \"Provided snapshot_id does not match canonical configuration\"\n            raise ValueError(msg)\n        sourced = groups or {\n            event: tuple((UNSOURCED, group) for group in event_groups)\n            for event, event_groups in config.hooks.items()\n        }\n        expanded: dict[HookEvent, tuple[HookHandler, ...]] = {}\n        compile_diagnostics: list[HookDiagnostic] = list(diagnostics)\n        for event, event_groups in sourced.items():\n            matcher_field = get_event_spec(event).matcher_field\n            handlers: list[HookHandler] = []\n            for group_index, (source, group) in enumerate(event_groups):\n                if matcher_field is None and group.matcher not in {None, \"\", \"*\"}:\n                    message = (\n                        f\"Rejected hook group {event.value}:{group_index}: \"\n                        f\"{event.value} does not support matchers\"\n                    )\n                    logger.warning(message)\n                    compile_diagnostics.append(\n                        HookDiagnostic(","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/code/deepagents_code/hooks/snapshot.py#L88-L124","documentation":"HooksSnapshot.from_config recomputes the canonical snapshot id from the config and, if a caller supplies an explicit snapshot_id, verifies it matches. A mismatch means the caller's cached/stored id was computed from different hook configuration, so the library refuses to build a snapshot under a misleading identity with ValueError.","triggerScenarios":"Calling HooksSnapshot.from_config(config, snapshot_id=\"...\", ...) where snapshot_id differs from compute_snapshot_id(config, groups=groups) — e.g. a persisted snapshot id reused after the project's hook config changed, or an id computed with different grouping.","commonSituations":"Editing .deepagents/hooks config while a session's cached snapshot id is still passed in; hand-rolling snapshot ids without compute_snapshot_id; stale trust-store or session metadata referencing an old config hash.","solutions":["Recompute the id: pass snapshot_id=None and use the returned snapshot's snapshot_id, or call compute_snapshot_id(config, groups=groups) and pass that.","If the config intentionally changed, invalidate cached sessions/trust entries and rebuild the snapshot from the new config.","Verify groups passed to from_config match those used when the id was originally computed.","Catch ValueError and fall back to rebuilding the snapshot without an explicit id."],"exampleFix":"// before\nsnap = HooksSnapshot.from_config(config, snapshot_id=old_cached_id)  # ValueError\n\n// after\nsnap = HooksSnapshot.from_config(config)  # id computed canonically\nuse(snapshot_id=snap.snapshot_id)","handlingStrategy":"validation","validationCode":"canonical = compute_snapshot_id(config, groups=groups)\nif cached_snapshot_id is not None and cached_snapshot_id != canonical:\n    cached_snapshot_id = None  # rebuild rather than fail","typeGuard":null,"tryCatchPattern":"try:\n    snap = HooksSnapshot.from_config(config, snapshot_id=cached_id)\nexcept ValueError as exc:\n    if \"does not match canonical configuration\" in str(exc):\n        snap = HooksSnapshot.from_config(config)  # recompute id","preventionTips":["Never persist and reuse snapshot ids after editing hook config","Compute ids only via compute_snapshot_id","Pass snapshot_id=None unless verifying an externally stored id","Invalidate cached sessions when hook config changes on disk"],"tags":["hooks","snapshot","integrity-check"],"backgroundTag":"snapshot-id-mismatch","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}