abhigyanpatwari/GitNexus · error · ValueError

overlay destination drifted before apply: {replacement['targ

Error message

overlay destination drifted before apply: {replacement['target']}

What it means

Thrown in the pre-publication loop of `apply_promoted_overlay` when, after staging candidate and backup files but before any exchange, a target's current on-disk state no longer equals its `base_state` captured during preparation. This detects concurrent edits that landed in the window between prepare and publish.

Source

Thrown at eval/workflow_bench/promotion_apply.py:738

                replacement["backup"] = _stage_replacement_at(
                    item["parent_descriptor"],
                    item["original"],
                    item["mode"],
                )
            except _StagingCleanupError as stage_exc:
                replacement["backup"] = stage_exc.name
                raise
        # Recheck the entire compare set after staging and before the first
        # replacement, then check each member immediately before its swap.
        _validate_prepared_paths(
            repo_root,
            root_descriptor,
            replacements,
            phase="pre-publication",
        )
        for replacement in replacements:
            if current_state(replacement) != replacement["base_state"]:
                raise ValueError(f"overlay destination drifted before apply: {replacement['target']}")
        for replacement in replacements:
            _validate_prepared_paths(
                repo_root,
                root_descriptor,
                [replacement],
                phase="publication",
            )
            if current_state(replacement) != replacement["base_state"]:
                raise ValueError(f"overlay destination drifted during apply: {replacement['target']}")
            previous_identity = _entry_identity_at(
                replacement["parent_descriptor"],
                replacement["name"],
            )
            replacement["publication_previous_identity"] = previous_identity
            try:
                _exchange_at(
                    replacement["parent_descriptor"],
                    replacement["candidate"],

View on GitHub (pinned to d540b00184)

Solutions

  1. Re-capture `expected_target_bases` and `expected_digest`, then retry the apply — the new capture will include the concurrent edit.
  2. Serialize promotion: ensure no other writer (formatter, IDE, build) runs against the repo during apply.
  3. Take a working-tree lock (e.g. `.git/index.lock` convention or a harness-level mutex) around capture+apply.
  4. If a specific tool is the culprit (ruff/black/prettier), disable it for the repo or run promotion in a clean checkout.

Example fix

# before: apply raced with an editor autosave
apply_promoted_overlay(overlay, expected_target_bases=bases)  # -> ValueError drifted
# after: serialize promotion and re-capture after any concurrent edit
import fcntl
with open(repo_root / '.wfbench-promote.lock', 'w') as lock:
    fcntl.flock(lock, fcntl.LOCK_EX)
    bases = destination_base_digests(overlay)
    apply_promoted_overlay(overlay, expected_target_bases=bases)
Defensive patterns

Strategy: validation

Validate before calling

import fcntl, contextlib
from workflow_bench.promotion_apply import destination_base_digests

@contextlib.contextmanager
def promote_lock(repo_root):
    with open(repo_root / ".wfbench-promote.lock", "w") as f:
        fcntl.flock(f, fcntl.LOCK_EX)
        yield

# hold the lock across capture+apply so no writer can drift a target
with promote_lock(repo_root):
    bases = destination_base_digests(overlay)
    apply_promoted_overlay(overlay, expected_target_bases=bases)

Type guard

null

Try / catch

try:
    apply_promoted_overlay(overlay, expected_target_bases=bases)
except ValueError as exc:
    if "drifted before apply" in str(exc):
        # a concurrent writer landed: re-capture and retry under a lock
        with promote_lock(repo_root):
            bases = destination_base_digests(overlay)
            apply_promoted_overlay(overlay, expected_target_bases=bases)
    raise

Prevention

When it happens

Trigger: A concurrent process (IDE formatter, build tool, another git operation, an editor autosave) modified one of the destination files between `_prepare_targets` and the `current_state(replacement) != base_state` check at promotion_apply.py:737. The promote operation aborts before doing any exchange.

Common situations: An IDE autosaves a file mid-promotion; a `pre-commit` hook or formatter runs in parallel; a developer edits a target while CI is promoting; background indexing rewrites a file; another `apply_promoted_overlay` call raced on the same repo.

Related errors


AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12). Data as JSON: /api/errors/dc5fa8a9a35e1e3c. Report an issue: GitHub.