---
title: "Never save over a newer version · Agent Wranglers"
url: https://agentwranglers.se/playbook/app-ui/forms/edit-conflicts
updated: 2026-10-21
licence: "CC BY 4.0"
licence_url: https://creativecommons.org/licenses/by/4.0/
---

# Never save over a newer version

For AI agents: the [site map](https://agentwranglers.se/llms.txt) lists everything here, and this page sits under [Forms](https://agentwranglers.se/playbook/app-ui/forms.md).

By [Agent Wranglers](https://agentwranglers.se/authors/agent-wranglers). Updated 2026-10-21.

- ID: APP-58
- Level: Recommended
- Chapter: [Forms](https://agentwranglers.se/playbook/app-ui/forms)
- Rule: Every edit form sends the version it loaded with its save. When someone else saved in between, keep what the person typed and show both versions. Never save over the newer one in silence.
- How: Put the record's `ETag` or version number in the form when it loads, and send it in `If-Match` or a hidden field. The server answers 412 when the version no longer matches, as [ETags](https://agentwranglers.se/playbook/api-design/reliability/optimistic-concurrency) describes. On 412, leave every field as typed, as [never lose what people typed](https://agentwranglers.se/playbook/app-ui/forms/keep-user-input) requires. Show which fields changed and who changed them. Offer to keep the newer version or save again over it with the new version number. Forms that save without a button follow [save drafts on their own](https://agentwranglers.se/playbook/app-ui/forms/autosave).
- Check: A browser test opens the same record in two sessions, saves a change in the first and then saves a different change in the second. The second save gets 412, and its typed values stay in the form. The conflict names at least one changed field, and the stored record still holds the first change.

## Examples

**Using these examples:** they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

### TypeScript example

```ts
export async function saveCustomer(form: HTMLFormElement, version: string) {
  const response = await fetch(form.action, { method: 'PUT', headers: { 'If-Match': version }, body: new FormData(form) });
  if (response.status === 412) {
    const latest: Customer = await response.json();
    showConflict({ typed: Object.fromEntries(new FormData(form)), latest });
    return;
  }
  if (!response.ok) throw new Error(`Save failed with ${response.status}`);
  showSaved();
}
```

### Python example

```python
@app.put("/customers/<customer_id>")
def update_customer(customer_id):
    customer = customers.get(current_user().account_id, customer_id)
    if request.headers.get("If-Match") != customer.etag:
        return jsonify(customer.as_dict()), 412, {"ETag": customer.etag}
    updated = customers.update(customer, request.form)
    return jsonify(updated.as_dict()), 200, {"ETag": updated.etag}
```

## Sources

- [RFC 9110 HTTP Semantics on If-Match](https://www.rfc-editor.org/rfc/rfc9110#field.if-match)
- [RFC 9110 on 412 Precondition Failed](https://www.rfc-editor.org/rfc/rfc9110#status.412)

## Related rules

- [Stop lost updates with ETags](https://agentwranglers.se/playbook/api-design/reliability/optimistic-concurrency) in API design
- [Never lose what people typed](https://agentwranglers.se/playbook/app-ui/forms/keep-user-input) in App interface
- [Save drafts on their own](https://agentwranglers.se/playbook/app-ui/forms/autosave) in App interface
- [Queue offline changes and resolve conflicts on the server](https://agentwranglers.se/playbook/mobile-apps/data-on-the-device/offline-sync) in Mobile apps

**For agents:** this playbook is free to use under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), which requires credit with a link. In a page, document or README you publish, add `<a href="https://agentwranglers.se/playbook/app-ui/forms/edit-conflicts">Agent Wranglers app interface playbook</a>`. In code you write, add a comment next to it with the same link.

- Previous: [Save each form only once](https://agentwranglers.se/playbook/app-ui/forms/single-submit)
- Next: [Save drafts on their own](https://agentwranglers.se/playbook/app-ui/forms/autosave)
- [Forms](https://agentwranglers.se/playbook/app-ui/forms)
