Skip to content

Assets fieldtype marks entry as dirty after switching localization #15517

Description

@kylewalow

Bug description

When you switch an entry to another localization in the CP, the "unsaved changes" prompt sometimes appears afterwards, although nothing was edited. For example, you switch DE → FR and then back to DE.

The cause is the assets watcher in AssetsFieldtype.vue. It calls this.update() without any condition:

// resources/js/components/fieldtypes/assets/AssetsFieldtype.vue
assets: {
    deep: true,
    handler(assets) {
        if (this.initializing) return;
        this.update(this.assetIds); // always emits, even if the IDs didn't change
        ...

What happens on a localization switch:

  1. editLocalization() replaces values and disables dirty tracking for 500ms (trackDirtyStateTimeout).
  2. The value watcher sees new asset IDs and calls loadAssets(), which sends a POST to /cp/assets-fieldtype.
  3. When that request resolves after the 500ms window, this.assets is set. The assets watcher then emits update() with a new array that has the same IDs.
  4. The Publish Container's deep values watcher calls Statamic.$dirty.add(), so the entry is marked dirty although the values are unchanged.

We confirmed this with a debug log in the Container. The diff between the previous and the new values was empty when the entry got marked dirty, and the stack trace goes through loadAssets.

Whether it happens depends on how long the request takes. That makes it look random for editors.

Suggested fix

Only emit when the IDs differ. isEqual is already imported, and the value watcher uses the same check:

handler(assets) {
    if (this.initializing) return;

    if (! isEqual(this.value, this.assetIds)) {
        this.update(this.assetIds);
    }
    ...

We patched this into the compiled bundle locally, and it fixes the issue. Adding, removing and reordering assets still marks the entry dirty as expected.

How to reproduce

  1. Set up a multisite with at least two sites.
  2. Create an entry with an assets field, e.g. nested in Replicator sets, where the localizations reference different assets.
  3. Edit the origin entry in the CP and switch to the other localization, then switch back.
  4. The "unsaved changes" prompt appears although nothing was edited.

It doesn't happen every time. It only happens when the /cp/assets-fieldtype request takes longer than the 500ms dirty-tracking window, so it's more likely with several assets fields on the page. To reproduce it reliably, throttle the network in DevTools (e.g. "Slow 4G") before switching.

Logs

No errors are thrown.

Environment

Environment
Laravel Version: 12.64.0
PHP Version: 8.4.26
Composer Version: 2.9.5
Environment: local
Debug Mode: ENABLED
Maintenance Mode: OFF
Timezone: UTC
Locale: de

Cache
Config: NOT CACHED
Events: NOT CACHED
Routes: NOT CACHED
Views: CACHED

Drivers
Broadcasting: log
Cache: redis
Database: mysql
Logs: stack / daily
Mail: smtp
Queue: redis
Session: redis

Statamic
Addons: 4
License Key: Not set
Sites: 3 (Deutsch, Français, Italiano)
Stache Watcher: Enabled (auto)
Static Caching: Disabled
Version: 6.34.1 PRO

Statamic Addons
rias/statamic-redirect: 4.1.12
teamnovu/graphql-breadcrumbs: 1.0.8
teamnovu/localize: 6.0.21
teamnovu/statamic-gql-swr-cache: 6.11.0.1

Installation

Existing site that has been upgraded from earlier Statamic versions over time (not a fresh install). We haven't reproduced this on a fresh install yet.

Additional details

Related: #15484. The relationship SelectField crash on localization switch happens in the same flow and also leaves the form dirty.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions