Skip to content

[4.x] Fix mergeNewSnapshot corrupting ephemeral data when array keys contain dots#10029

Merged
calebporzio merged 9 commits intomainfrom
josh/fix-dot-containing-keys-snapshot-merge
Mar 17, 2026
Merged

[4.x] Fix mergeNewSnapshot corrupting ephemeral data when array keys contain dots#10029
calebporzio merged 9 commits intomainfrom
josh/fix-dot-containing-keys-snapshot-merge

Conversation

@joshhanley
Copy link
Copy Markdown
Member

The Scenario

When a component uses PHP array keys that contain dots, the second interaction with the component throws an error. The first click works fine, but any subsequent request fails with "Undefined array key":

ErrorException - Internal Server Error
Undefined array key "show"
<?php

use Livewire\Component;

new class extends Component {
    public array $articles = [];

    public function mount(): void
    {
        $this->articles['order.foo'] = ['show' => 'abc'];
    }

    public function addSomething(): void
    {
        $this->articles['order.foo.bar'] = ['show' => 'ghl'];
    }

    public function addSomethingAgain(): void
    {
        $this->articles['order.foo.lol'] = ['show' => 'xyz'];
    }
};
?>

<div>
    <flux:button wire:click="addSomething">test</flux:button>
    <flux:button wire:click="addSomethingAgain">test again</flux:button>
    <ul>
        @foreach($articles as $key => $value)
            <li>{{ $key }}: {{ $value['show'] }}</li>
        @endforeach
    </ul>
</div>

The Problem

The mergeNewSnapshot method in js/component.js applies server changes to the client's reactive state using dataGet/dataSet with dot-notated path strings:

changes.forEach(key => {
    dataSet(this.reactive, key, dataGet(newData, key))
})

When the diff() function encounters an array key like order.foo.bar, it builds a path string "articles.order.foo.bar". dataGet and dataSet then split this on ALL dots, interpreting it as 4 nested levels (articlesorderfoobar) instead of 2 levels (articlesorder.foo.bar).

This corrupts this.ephemeral/this.reactive by creating spurious nested objects, causing subsequent requests to send malformed data to the server.

The Solution

Replaced the flat-diff + dataGet/dataSet approach with a recursive tree-walking function (applyServerChanges) that compares old and new server state and applies differences directly via obj[key] access — never constructing or parsing dot-notated path strings.

The new approach achieves the same granularity as the previous implementation (only updating properties the server actually changed, preserving client-side ephemeral state) while correctly handling keys that contain dots.

Fixes #10026

@calebporzio calebporzio merged commit 1b15f48 into main Mar 17, 2026
63 of 64 checks passed
@calebporzio calebporzio deleted the josh/fix-dot-containing-keys-snapshot-merge branch March 17, 2026 18:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants