Conflict Resolution When Multiple Agents Update Shared State
Write-time conflict detection catches agent contradictions before they corrupt shared state.

Multi-agent AI systems fail in a specific, recurring way: two or more agents produce answers that contradict each other, and nothing in the system notices. That's the subject of this piece. Shared state is what lets agents collaborate, and it's also exactly where the collaboration comes apart, because letting multiple processes read and write the same data concurrently trades away the single-writer guarantee that makes correctness checkable. Research from 2025 and 2026 puts numbers on the damage: failure rates between 41% and 86.7% across popular multi-agent benchmarks, with nearly 79% of those failures traced to specification and coordination problems rather than any shortfall in the underlying model. That last point changes where engineering effort should go: a better model does not fix an interleaved write. Only better coordination architecture does.
The failure modes that occur in concurrent agent systems
The most common failure is the plainest one. Agent 1 reads a piece of shared state, spends time processing it, and writes its result. Agent 2 does the same thing on an overlapping slice of state, and its write lands second, silently erasing Agent 1's work. No exception fires. No log entry flags it. The system just produces a wrong answer as though it were a correct one, which is worse than crashing, because crashes get investigated and silent overwrites don't.
Stale state propagation is a close cousin. Picture an order fulfillment pipeline: Agent A marks an order "paid," and before that update becomes visible, Agent B reads the pre-update status and declines to allocate inventory for it. Both agents acted reasonably given what they saw. The output is still contradictory, and again, no exception gets raised, because nothing in the architecture was watching for the mismatch.
A third pattern is specific to how LLM agents work rather than software in general. Traditional concurrency bugs happen inside windows measured in microseconds. An LLM agent's "transaction" includes an inference phase that can run for minutes: Agent A reads a file like utils.py, then enters a long reasoning pass. While that reasoning is underway, Agent B refactors the same file and renames a function Agent A was depending on. By the time Agent A finishes and writes, it's referencing a name that no longer exists. It's a textbook stale-read hazard, except the window in which it can occur is vastly wider than in conventional systems, simply because LLM inference takes so much longer than a database read.
The fourth failure mode is the hardest to catch by any mechanical means. Two agents each produce code that compiles cleanly on its own. Combined, it breaks. These are semantic conflicts, and no line-level diff tool can see them coming, because nothing about the text of either change looks wrong in isolation. The failure only exists at the level of meaning, and meaning is precisely what merge tools don't read.
Why classical concurrency control transfers poorly to LLM agents
None of this is a new problem in the abstract. Two processes mutating shared state is a concurrency question software engineering has dealt with for decades, and the textbook toolkit, locks, transactions, isolation levels, is well understood. What's different with LLM agents is the parameters, and the mismatch is severe enough to break most of that toolkit.
Start with duration. A traditional database transaction holds a lock for milliseconds. An LLM agent's equivalent "transaction" can span minutes of inference. Lock an agent out of a shared resource for that long and the whole point of running agents in parallel evaporates, because everyone else is now waiting on one slow thinker.
Then there's the question of what an agent is even going to touch. Classical concurrency control depends on being able to statically infer a transaction's read set before it runs, so the system can predict conflicts in advance. LLM agents don't offer that. Their read sets are broad, dynamic, and only fully known in hindsight, which makes advance conflict prediction unreliable at best.
Finally, a lot of the state agents act on can't be forked, snapshotted, or buffered for later reconciliation. Production databases and live infrastructure take a write the moment it executes; there's no sandbox copy to reconcile later. That rules out entire categories of concurrency control that depend on deferred, buffered writes.
LLM agents also carry overhead that traditional concurrent systems never had to budget for. Every lock acquisition becomes a tool call. Every concurrency primitive an agent has to reason about consumes context window space and demands prompting or fine-tuning that adds real engineering cost. Mechanisms that ask an agent to explicitly track and manage locks require a level of model sophistication that transparent, system-level enforcement simply doesn't need.
Pessimistic two-phase locking illustrates the mismatch concretely. In testing, it produced deadlocks at a rate of 0.81 per run and recovered almost none of the expected speedup from parallelism, landing barely above serial execution. The cost of blocking through long inference intervals eats the very benefit concurrency was supposed to deliver.
How deferred merge strategies displace the conflict problem
The default answer to all of this has been workspace isolation: give each agent its own git worktree, let it work undisturbed, and reconcile everything at merge time. It solves one problem cleanly. Agents don't step on each other mid-edit. But it doesn't remove the conflict, it just relocates it to a point after both agents have already committed to designs that might be fundamentally incompatible.
Git merge is good at exactly one thing: catching textual line conflicts. What it can't see are semantic conflicts, where both branches compile individually but break in combination, interface mismatches between what one agent expected and what another delivered, or invariants that only make sense when you look at both agents' writes together. None of that is visible as a conflict marker.
The usual fix layered on top is an LLM-based reviewer that inspects the merged output after the fact and tries to reconcile it. That reviewer has a genuinely hard job: reconstructing each agent's original intent purely from the merged result, with none of the reasoning context either agent had while it was actually writing the code. Stripped of that context, the reconstruction usually fails, because intent doesn't survive the merge, only its output does.
The damage compounds, too. Because agents worked in isolation with no visibility into what their peers were doing, conflicts don't surface one at a time, they accumulate. Agent A writes a helper function assuming a certain signature. Agent B, working in its own branch, changes that signature for its own reasons. Neither branch shows any sign of trouble on its own. The breakage only exists in the union of the two, and by the time anyone finds it, both agents have moved well past the decision that caused it.
Write-time detection and why the timing difference is structural
Write-time detection flips the sequence. Instead of letting each agent write freely and sorting it out later, a coordination layer intercepts every proposed write before it commits. It checks whether the read dependencies the agent relied on have changed since the agent last looked at them. If nothing's changed, the write commits. If something has changed, the write gets rejected and the agent receives the updated state, so it can retry from a correct baseline rather than from the point where it failed.
STORM's formulation of this makes an important simplification: an agent doesn't need a frozen, global snapshot of the entire workspace. It only needs assurance that the specific files feeding its current edit are still current. That's a narrower guarantee than full serializable isolation, and it's exactly narrow enough to be practical.
The timing matters structurally. A write rejected at write time throws away one action. The agent still has its reasoning intact and can redo the specific step that failed. A conflict caught only at merge time throws away, or at minimum forces a full re-examination of, everything both agents produced across the entire session. One is a local correction. The other is a teardown.
This architectural shift can be captured as a simple substitution: instead of an agent writing to shared state directly, it proposes changes to a coordination layer. Agents stop writing to shared state and start proposing changes to it, and the coordination layer decides, checking for concurrent modifications before anything is actually committed. That one substitution is the entire pattern.
Research systems that operationalize write-time detection
STORM mediates every file read and write an agent performs. Before it accepts a write, it checks whether the target file, or anything the agent's write depends on, has changed since the agent last observed it. A conflict triggers a rejection and a return of updated content, so the agent retries with current information. No workspace isolation is required.
The results are notable. On Commit0-Lite, STORM reached an 82.5% macro pass rate and 46.2% weighted pass rate, against 63.8% and 24.6% for a GitWorktree baseline and 66.4% and 20.7% for a single-agent baseline, an 18.7-point improvement over git-worktree on that benchmark. On PaperBench, STORM scored 74.1 against GitWorktree's 72.7 and a single-agent baseline of 68.7. Combined with single-agent runs, STORM's approach reached 87.6 on Commit0-Lite and 78.2 on PaperBench. It's architecture-agnostic: it can be dropped into an existing multi-agent system rather than requiring a rebuild around it.
CoAgent takes a different path: optimistic execution paired with a notification layer. Agents execute without waiting for locks, but get notified when a concurrent action might affect their own isolation. The notified agent judges the conflict's actual relevance and patches only the affected actions. Out-of-order writes get undone and reapplied using registered inverse operations.
The results back the design up. CoAgent passed all ten of its contended test workloads with correctness within 5% of fully serial execution, at a solid speedup and token cost only modestly above serial. Compare that to naive optimistic concurrency control, which ran slower than serial while costing several times the tokens. Even on a budget model, DeepSeek v4 flash, agents misjudged notification relevance in only 5% of trials, and the protocol maintains correctness as long as agents follow its mechanical rules.
MPAC addresses a gap in existing agent communication protocols. Both MCP and A2A assume a single controlling principal is coordinating things, an assumption that breaks down once you have genuinely peer agents. MPAC adds structured intent declaration as a precondition for taking any action, and treats conflicts as first-class structured objects rather than incidental errors, with a pluggable human-in-the-loop governance layer sitting above it. Pre-announcing intent this way produced a 95.6% reduction in coordination overhead and a wall-clock speedup of several times over on a three-agent, cross-module code review task.
AgentRoom builds a structured runtime object around file-level claim semantics, an append-only broadcast log, and per-agent status tracking. Agents negotiate ownership and intent explicitly through MCP tools, room_claim, room_release, room_state, room_broadcast, room_read, before acting, layered on top of a CRDT-merged shared filesystem for structural convergence. The explicit negotiation stands in deliberate contrast to observation-driven approaches, where agents infer what's happening rather than declare it.
Where hybrid and CRDT-backed approaches fit
CRDTs (conflict-free replicated data types) handle one part of this problem well: convergence, when operations actually commute. CodeCRDT guarantees full convergence with zero merge failures, and agents can observe shared CRDT state directly to skip work a peer has already done.
That guarantee has a ceiling, though. In CodeCRDT, somewhere between 5% and 10% of merges produce semantic conflicts that the merge function has no way to resolve on its own, because commutativity at the data-structure level says nothing about correctness at the level of meaning. An LLM-driven arbiter sits above the CRDT layer specifically to catch that residual category. Running agents in parallel under this setup improves runtime by 25%, but comes with a 7.7% drop in code quality.
Stripping out the arbiter and relying on implicit CRDT coordination alone makes the results inconsistent: a 21% speedup on some tasks, a 39% slowdown on others. That spread says something important on its own: structural convergence is necessary but not sufficient whenever semantic coherence is actually what's at stake.
Last-write-wins remains a legitimate option, but only for a narrow band of workloads: low-stakes, append-heavy cases where the cost of building real conflict resolution outweighs the cost of occasionally accepting a stale write. Outside that band, on anything semantically interdependent, last-write-wins is unsafe, and there's no version of the strategy that changes that.
What an engineering team should build or adopt to prevent write-time conflicts
The foundational principle is sequencing: conflict resolution belongs in the initial design, not bolted on after a system is already in production. Retrofitting a coordination layer into an architecture built around direct shared-state writes is structurally expensive, closer to a rebuild than a patch, because the direct-write pattern is baked into every agent's assumptions about how state behaves.
The place to start is the coordination layer pattern itself: agents propose state changes to a mediating layer instead of writing directly, the layer checks proposals against concurrent changes, resolves conflicts according to policy, and commits atomically. That cause is the architectural primitive underneath STORM and CoAgent alike, and it holds regardless of which specific framework or vendor tooling ends up implementing it.
From there, the right consistency guarantee depends on the workload rather than on a single default. Commutative operations over shared data structures are a good fit for a CRDT-backed layer with an LLM arbiter handling the semantic residuals CRDTs can't resolve on their own. Highly contended, high-concurrency workloads with real interdependence point toward write-time mediation of the kind STORM and CoAgent operationalize, where the coordination layer checks read dependencies before a write commits rather than after. Low-stakes, append-heavy workloads may not need any of this machinery at all, and last-write-wins remains defensible there, precisely because the cost of an occasional stale write is genuinely low.
What ties all of it together is the timing principle stated earlier: catching a conflict before a write commits discards one action, while catching it after a merge discards, or at least forces a full re-audit of, everything built on top of it. Every design decision in this space ultimately reduces to which side of that line a system is built to catch failure on.


