abhigyanpatwari/GitNexus · critical · RuntimeError
post-apply parity check failed: {replacement['target']}
Error message
post-apply parity check failed: {replacement['target']} What it means
Thrown in the post-apply loop after every individual exchange passed its own parity check. The full re-validation across all replacements found at least one whose destination/candidate slot identity or state drifted, meaning something changed the entries between their individual swaps and the final global check.
Source
Thrown at eval/workflow_bench/promotion_apply.py:810
)
if (
observed_destination == replacement["candidate_state"]
and observed_previous == replacement["base_state"]
and destination_identity == replacement["candidate_identity"]
and displaced_identity == previous_identity
):
continue
raise RuntimeError(f"atomic overlay exchange parity check failed: {replacement['target']}")
for replacement in replacements:
if (
current_state(replacement) != replacement["candidate_state"]
or entry_state(replacement, replacement["candidate"]) != replacement["base_state"]
or _entry_identity_at(replacement["parent_descriptor"], replacement["name"])
!= replacement["candidate_identity"]
or _entry_identity_at(replacement["parent_descriptor"], replacement["candidate"])
!= replacement["publication_previous_identity"]
):
raise RuntimeError(f"post-apply parity check failed: {replacement['target']}")
_validate_prepared_paths(
repo_root,
root_descriptor,
replacements,
phase="post-apply validation",
)
published_all = True
except BaseException as exc:
rollback_failures: list[str] = []
for replacement in reversed(completed):
try:
destination_identity = _entry_identity_at(
replacement["parent_descriptor"],
replacement["name"],
)
temporary_identity = _entry_identity_at(
replacement["parent_descriptor"],
replacement["candidate"],View on GitHub (pinned to d540b00184)
Solutions
- Serialize the entire apply (capture + publish + verify) under an exclusive lock so no writer can interleave.
- Run promotion in a clean, isolated checkout that no IDE/build touches.
- After a clean rollback (see error 414) re-capture evidence and retry.
- Investigate the specific target named in the message for a process that writes it post-swap.
Example fix
# before: post-apply global check found drift
apply_promoted_overlay(overlay, expected_target_bases=bases) # -> RuntimeError
# after: isolate + lock so no writer can land between swap and final check
with promote_lock(repo_root): # see error 410 example
apply_promoted_overlay(
overlay,
expected_target_bases=destination_base_digests(overlay),
) Defensive patterns
Strategy: validation
Validate before calling
# post-apply drift means a writer landed during the apply — same lock as 409/410.
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
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 RuntimeError as exc:
if "post-apply parity check failed" in str(exc):
# rollback should have run; verify tree then re-capture+retry under lock
import subprocess; subprocess.run(["git", "-C", str(repo_root), "status"], check=False)
raise Prevention
- Hold the lock across the entire apply including the post-apply verification loop.
- Confirm `git status` is clean after a post-apply rollback before retrying.
- Treat a post-apply parity failure as evidence of a concurrent writer — find and silence it.
When it happens
Trigger: All swaps succeeded individually, but a concurrent writer (or filesystem behavior) altered one or more slots before the global post-apply verification at promotion_apply.py:801-810. Triggers rollback of completed replacements.
Common situations: Concurrent editor/formatter touched a target after its swap but before the final loop; background indexer; an IDE 'restore' that overwrote a just-promoted file; same root causes as 409/410 but landing late.
Related errors
- overlay destination drifted during apply: {replacement['targ
- overlay destination parent changed during {phase}: {item['ta
- overlay destination drifted before apply: {replacement['targ
- Analyzer build or dependency runtime changed during analysis
- {label} changed while being read: {path}
AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12).
Data as JSON: /api/errors/0cd08cebf6dbde8b.
Report an issue: GitHub.