Unity Cloud Save Conflict Resolution Overwrites Newer Data - Last-Write and Merge Strategy Fix - How to Fix

Problem: Players report lost progress, rolled-back inventory, or settings that revert after playing on another device. Your logs show successful Cloud Save writes, yet the newer session clearly did not win.

This pattern almost always means your client treated local state as authoritative and wrote it back over a newer server snapshot without a real merge.

Problem signature

Look for one or more of these together:

  • second device opens the game and briefly shows old progress, then “syncs” away newer work from the first device
  • you save immediately on login before loading Cloud Save keys for that profile
  • you always use the same conflict policy without branching per key (progression vs cosmetics vs settings)
  • QA cannot reproduce on one machine, but two accounts or two devices expose it quickly
  • telemetry shows two writes close together with descending logical progression (chapter, level index, currency) even though the player was advancing

Root cause

Unity Cloud Save stores per-key values in the cloud. If your flow is effectively “take whatever is in memory and push it,” you are doing implicit last-writer-wins at upload time, not “keep the best player state.”

Common failure modes:

  1. Save-before-load on session start
    The local cache from the last machine session is still in RAM. You write it before the async load finishes, so the cloud copy that contained the other device’s newer run gets replaced.

  2. Stale in-memory model after a failed or skipped load
    A network hiccup causes you to skip the load path, but you still autosave ten seconds later.

  3. Whole-blob replace on partial reads
    You load three keys but persist twenty. The write uploads a JSON blob assembled from defaults plus partial data, erasing fields that only existed on the server.

  4. No conflict-aware retry
    When the service signals a conflict (or you always force overwrite), you never run a merge function. The newest logical progress is not the same as “who uploaded last.”

  5. Clock skew and naive timestamps
    Using device local time as the only merge key is fragile. Prefer server-stamped metadata from Cloud Save responses when deciding which branch to keep.

Step-by-step fix

1) Enforce load-merge-save on every cold start

Before any autosave runs on a fresh process:

  1. Authenticate the player for Unity Gaming Services the same way you do for Cloud Save.
  2. Load the keys you own (or a manifest list) and wait for completion.
  3. Merge into your local model (see step 3).
  4. Only then enable autosave timers or scene transitions that persist state.

If you need an emergency local-only mode, gate saves so they cannot call Cloud Save until the first successful load completes or the player explicitly chooses offline.

2) Split keys by merge policy

Do not treat every field the same.

Suggested grouping:

  • High risk (needs merge rules): currency, inventory stacks, quest flags, chapter index
  • Medium risk: cosmetics, loadouts (often safe with “replace if newer by version”)
  • Low risk: graphics settings (usually safe with last-writer if you accept rare cross-device preference fights)

Document the rule per key in your internal wiki so future features do not default to “dump JSON.”

3) Implement a real merge for structured saves

For JSON-like blobs:

  1. Deserialize server and local into the same schema.
  2. For each risky field, apply an explicit rule:
    • Counters or currency: take the maximum of the two values only if your design guarantees monotonicity; otherwise use server-wins plus a support-safe transaction log.
    • Sets (unlocked achievements, collected IDs): take the union.
    • Linear progression flags: prefer the highest completed step index if your quest graph is strictly linear; for branching quests, prefer server wins unless you store a version vector per branch.
  3. Serialize the merged result and write once.

If two fields can contradict each other after a naive max rule, tighten the schema instead of guessing in production.

4) Use conflict-aware writes instead of blind overwrite

When the Cloud Save API exposes conflict behavior, prefer paths that let you detect mismatch instead of silently clobbering:

  • On conflict or failed write because the remote changed, reload the key, rerun merge, and retry a bounded number of times with backoff.
  • Log the key name, local version metadata, and remote metadata in your diagnostics channel (without dumping personal data).

Exact enum and method names drift by package version, so align your code with the Cloud Save package version pinned in your manifest.json and the official Unity documentation for that version.

5) Add a two-client QA script

  1. Two builds or two devices on the same test account.
  2. Device A completes an action that bumps a high-signal stat (for example, level or currency).
  3. Confirm Cloud Save shows the bump in the dashboard or via a debug read.
  4. Device B launches from cold start, performs a different bump, saves.
  5. Device A relaunch: both bumps must coexist according to your merge rules, with no silent regression of the earlier bump.

If step 5 fails, return to step 1 and verify no save runs before load completion.

Verification checklist

  • [ ] Cold start path has zero Cloud Save writes before the first successful load of governed keys.
  • [ ] Autosave cannot fire during the loading window unless it writes local-only scratch data that never overwrites cloud keys.
  • [ ] Each high-risk key has a documented merge rule and a unit test or editor test with two JSON fixtures.
  • [ ] Two-device QA passes on Wi-Fi off or flaky mode (airplane toggle) without duplicate progression loss.
  • [ ] Logs show conflict retries resolving to the merged payload, not endless loops.

Alternative fixes and mitigations

  • Server-authoritative economy: move currency and purchases to a remote config / economy backend so clients only request mutations, not absolute balances, if cheating or conflicts are unacceptable.
  • Smaller keys: splitting one giant blob into keys per subsystem reduces the blast radius when a merge fails.
  • Feature flag: disable cross-device sync for a milestone while you ship single-device saves, but communicate it clearly to players.

Prevention tips

  • Treat Cloud Save like a database row: never update without reading the row you intend to supersede.
  • Add CI or nightly editor tests that deserialize two fixtures and assert merge output.
  • Pair Cloud Save work with the same discipline you use for remote catalogs: see Unity Addressables Remote Catalog Hash Mismatch After CDN Purge for a related “remote state must be consistent” mindset, even though the services differ.

Related problems

Bookmark this page if you ship on multiple devices or plan cross-progression between desktop and mobile builds.

FAQ

Is “last writer wins” always wrong?

No. It is acceptable for low-risk keys if players understand the tradeoff. It is risky for progression and economy unless you have another source of truth.

Should merges run on a background thread?

Prefer doing merge logic on the main thread or a controlled task queue tied to your game state model so you do not race Unity objects. Offload only CPU-heavy parsing if your profiler shows a need.

What if I only discover this after launch?

Ship a client update that adds the load gate and merge rules, run a one-time “repair read” on next login, and consider granting make-good currency if economy keys were corrupted. Document the incident for store compliance if purchases were affected.

Does Unity Cloud Save replace Steam Cloud?

They are different systems. If you use both, define which store owns which keys or you can double-write and still lose coherence. Pick one primary source of truth per platform family when possible.


If this helped you ship safer cross-device saves, share it with another developer on your team so the merge rules stay consistent across branches.