abhigyanpatwari/GitNexus · error · ValueError
overlay destination drifted during apply: {replacement['targ
Error message
overlay destination drifted during apply: {replacement['target']} What it means
Thrown in the per-replacement publication loop of `apply_promoted_overlay`. Right before each individual `_exchange_at` swap, the target's current state is re-checked against its base state; if it drifted mid-transaction (i.e. between the pre-publication check at :737 and this per-member check at :746), the apply aborts and rolls back completed swaps.
Source
Thrown at eval/workflow_bench/promotion_apply.py:747
# 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"],
replacement["name"],
)
except BaseException:
# A wrapper/interruption can raise after the atomic exchange.
# Classify by inode movement so a raced edit in the displaced
# slot cannot be mistaken for an exchange that never landed.
try:
destination_identity = _entry_identity_at(
replacement["parent_descriptor"],View on GitHub (pinned to d540b00184)
Solutions
- Eliminate the concurrent writer (same fixes as error 409 — serialize, lock, disable formatters).
- Re-capture `expected_target_bases` from the now-modified tree and retry — the CAS will bind to the new base.
- Run promotion in an isolated checkout no other process touches.
- If the loop is slow because of many targets, batch them or move the repo to faster storage to shrink the race window.
Example fix
# before: drifted during the per-member publication loop
apply_promoted_overlay(overlay, expected_target_bases=bases) # -> ValueError during
# after: hold an exclusive lock across capture+apply so no writer can interleave
import fcntl, contextlib
@contextlib.contextmanager
def promote_lock(repo):
with open(repo / '.wfbench-promote.lock', 'w') as f:
fcntl.flock(f, fcntl.LOCK_EX); yield
with promote_lock(repo_root):
apply_promoted_overlay(overlay, expected_target_bases=destination_base_digests(overlay)) Defensive patterns
Strategy: validation
Validate before calling
import fcntl, contextlib
@contextlib.contextmanager
def promote_lock(repo_root):
with open(repo_root / ".wfbench-promote.lock", "w") as f:
fcntl.flock(f, fcntl.LOCK_EX); yield
# the lock must span the ENTIRE apply, not just capture, to block mid-loop drift
with promote_lock(repo_root):
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 during apply" in str(exc):
# rollback completed cleanly (see 414); re-capture and retry under lock
with promote_lock(repo_root):
bases = destination_base_digests(overlay)
apply_promoted_overlay(overlay, expected_target_bases=bases)
raise Prevention
- The lock window must include the whole multi-target apply, not just the pre-checks.
- Keep the target set small to shrink the race window if you cannot fully lock.
- Move the repo to faster storage if many targets make the apply long.
When it happens
Trigger: A concurrent writer modified a target file after that target passed the pre-publication check but before its own exchange. Different from error 409 — here the drift happened *during* the multi-target apply loop, not before it.
Common situations: Long apply with many targets where a background process edits one of the later targets while earlier ones are being swapped; IDE autosave; CI running a formatter mid-apply; another promotion overlapping.
Related errors
- overlay destination drifted before apply: {replacement['targ
- post-apply parity check failed: {replacement['target']}
- overlay destination parent changed during {phase}: {item['ta
- overlay destination base binding mismatch:
- Analyzer build or dependency runtime changed during analysis
AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12).
Data as JSON: /api/errors/44b9413fa6f171e1.
Report an issue: GitHub.