{"record":{"id":"66f5ff8ced0de30d","repo":"abhigyanpatwari/GitNexus","slug":"overlay-destination-base-binding-mismatch","errorCode":null,"errorMessage":"overlay destination base binding mismatch: ","messagePattern":"overlay destination base binding mismatch: ","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"eval/workflow_bench/promotion_apply.py","lineNumber":646,"sourceCode":"    repo_root, root_descriptor, prepared = _prepare_targets(payload, repo_root)\n    current_bases = {item[\"target\"].as_posix(): item[\"base_digest\"] for item in prepared}\n    if expected_target_bases is not None and expected_target_bases != current_bases:\n        expected_paths = set(expected_target_bases)\n        current_paths = set(current_bases)\n        missing = sorted(current_paths - expected_paths)\n        unexpected = sorted(expected_paths - current_paths)\n        drifted = sorted(\n            path for path in current_paths & expected_paths if current_bases[path] != expected_target_bases[path]\n        )\n        details = []\n        if missing:\n            details.append(\"missing=\" + \",\".join(missing))\n        if unexpected:\n            details.append(\"unexpected=\" + \",\".join(unexpected))\n        if drifted:\n            details.append(\"drifted=\" + \",\".join(drifted))\n        _close_prepared(root_descriptor, prepared)\n        raise ValueError(\"overlay destination base binding mismatch: \" + \"; \".join(details))\n\n    replacements: list[dict[str, Any]] = []\n    completed: list[dict[str, Any]] = []\n    preserve_backups = False\n    published_all = False\n    rollback_complete = False\n\n    def entry_state(replacement: dict[str, Any], name: str) -> tuple[str, int]:\n        current, mode = _read_destination_at(\n            replacement[\"parent_descriptor\"],\n            name,\n            target=replacement[\"target\"],\n        )\n        return hashlib.sha256(current).hexdigest(), stat.S_IMODE(mode)\n\n    def current_state(replacement: dict[str, Any]) -> tuple[str, int]:\n        return entry_state(replacement, replacement[\"name\"])\n","sourceCodeStart":628,"sourceCodeEnd":664,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/d540b00184d71a896261ee02670da9a92d59d8f7/eval/workflow_bench/promotion_apply.py#L628-L664","documentation":"Thrown in `apply_promoted_overlay` when the caller passed `expected_target_bases` and the on-disk base digests differ from what was expected. The message enumerates which paths are missing, unexpected, or drifted, so you can see exactly how the working tree diverged from the promotion evidence.","triggerScenarios":"Calling `apply_promoted_overlay(overlay, expected_target_bases=<dict>)` after the destination files changed on disk (paths edited, added, removed, or their mirror targets changed). The diff of expected vs. current base digests is non-empty and the detailed `missing=`/`unexpected=`/`drifted=` breakdown is appended.","commonSituations":"A file was edited in the worktree after `destination_base_digests` was captured; a new file was added to the tree; a file was deleted; the overlay's `mirror_targets` mapping changed so the target set no longer matches; running apply against a different branch than the one evidence was captured on.","solutions":["Read the message: `drifted=` paths need re-capture, `missing=` paths are new on disk, `unexpected=` paths are gone — handle each category.","Re-capture `expected_target_bases` with `destination_base_digests(overlay)` immediately before apply and pass the fresh dict.","Restore the worktree to the state evidence was captured from (e.g. `git checkout -- .` or `git restore --source=<ref>`).","Ensure no concurrent writer (formatter, IDE, build) touches the repo between capture and apply."],"exampleFix":"# before: stale expected_target_bases from an earlier capture\napply_promoted_overlay(overlay, expected_target_bases=stale_bases)  # -> ValueError\n# after: re-capture fresh and apply atomically\nfrom workflow_bench.promotion_apply import destination_base_digests\nfresh = destination_base_digests(overlay)\napply_promoted_overlay(overlay, expected_target_bases=fresh)","handlingStrategy":"validation","validationCode":"from workflow_bench.promotion_apply import destination_base_digests\n\ndef current_target_bases_match(overlay, expected: dict[str, str]) -> bool:\n    return destination_base_digests(overlay) == expected\n\n# capture right before apply\nbases = destination_base_digests(overlay)\nassert current_target_bases_match(overlay, bases)\napply_promoted_overlay(overlay, expected_target_bases=bases)","typeGuard":"null","tryCatchPattern":"try:\n    apply_promoted_overlay(overlay, expected_target_bases=expected)\nexcept ValueError as exc:\n    if \"base binding mismatch\" in str(exc):\n        # parse drifted=/missing=/unexpected= and re-capture\n        bases = destination_base_digests(overlay)\n    raise","preventionTips":["Always capture `expected_target_bases` immediately before apply, in the same locked section.","Freeze the worktree (no edits, no formatters) between capture and apply.","Log the diff string from the message so you can see which paths drift when it happens."],"tags":["integrity","cas","drift","overlay","validation"],"backgroundTag":null,"analyzedSha":"d540b00184d71a896261ee02670da9a92d59d8f7","analyzedAt":"2026-08-12T19:50:25.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}