Skip to content

Fix "Snapshot missing" errors caused by unstable Livewire keys in the comment list#100

Open
ItsMalikJones wants to merge 3 commits into
mainfrom
fix/72-livewire-key-getcontenthash
Open

Fix "Snapshot missing" errors caused by unstable Livewire keys in the comment list#100
ItsMalikJones wants to merge 3 commits into
mainfrom
fix/72-livewire-key-getcontenthash

Conversation

@ItsMalikJones
Copy link
Copy Markdown

Fixes #72.

Problem

comment-list.blade.php keyed each child <livewire:dynamic-component> by
$comment->getContentHash(). For a Comment, getContentHash() returns
md5(body + reaction ids), which has two failure modes:

  1. Unstable — the hash changes whenever a comment is edited or reacted to,
    so the keyed component effectively re-keys itself mid-lifecycle.
  2. Collision-prone — two comments with identical content produce the same
    hash, so they share a wire:key.

Either case breaks Livewire's DOM reconciliation and surfaces as
Snapshot missing on Livewire component errors.

Reproduce: post two comments with identical bodies, or edit / react to an
existing comment in a list — the component throws "Snapshot missing".

Fix

Key each component by $comment::class . ':' . $comment->getId():

  • Stable — neither the class nor the primary key changes when a comment is
    edited or reacted to.
  • Unique per rowgetId() returns the primary key.
  • Namespaced by type — prefixing with the class prevents a Comment and a
    RenderableComment that happen to share a numeric id from colliding. This is
    a real scenario when getComments() is overridden to merge non-comment items
    into the list.

Deprecation

getContentHash() is no longer used anywhere in the package. It is marked
@deprecated on the Contracts\RenderableComment interface and both
implementations (Comment, RenderableComment). It is not removed — it is
part of the public contract, so removal is deferred to a future major version.

Tests

Three tests added to tests/Livewire/CommentListTest.php:

  • renders duplicate-content comments without key collision — two comments with
    identical bodies render distinct keys.
  • keeps comment keys stable across edits — a comment's key is unchanged after
    its body is edited.
  • renders Comment and RenderableComment sharing an id without key collision
    a Comment and a RenderableComment with the same id render distinct keys.

Backwards compatibility

No breaking changes. The wire:key value format is internal to Livewire's
rendering and is not a public API. getContentHash() remains callable
(deprecated only).

The list loop previously keyed each child component by
`$comment->getContentHash()` — an MD5 of body + reactions that
changes whenever a comment is edited or reacted to, and that
collides for two comments with identical content. Both cases
caused Livewire "Snapshot missing" errors after the keyed
component re-keyed itself mid-lifecycle.

`getId()` is stable across edits/reactions and unique per row,
which is what Livewire keys need.
Include the class name in Livewire component keys to prevent collisions
when Comment and RenderableComment instances share the same ID.

Mark `getContentHash()` as deprecated since it's no longer used for
key generation.
@ItsMalikJones ItsMalikJones self-assigned this May 16, 2026
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.

Livewire “Snapshot missing” error when using getContentHash() as :key in comment loop

1 participant