Skip to content

fix: emit each_key_duplicate error in production#16724

Merged
7nik merged 32 commits intomainfrom
fix-15339
Feb 4, 2026
Merged

fix: emit each_key_duplicate error in production#16724
7nik merged 32 commits intomainfrom
fix-15339

Conversation

@7nik
Copy link
Contributor

@7nik 7nik commented Sep 6, 2025

Closes #15339

It looks like duplicate keys cause crashing only in one place.
In some cases it still can successfully render the list but will crash soon anyway, so I don't see reasons to add other checks.

Before submitting the PR, please make sure you do the following

  • It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs
  • Prefix your PR title with feat:, fix:, chore:, or docs:.
  • This message body should clearly illustrate what problems it solves.
  • Ideally, include a test that fails without this PR but passes with it.
  • If this PR changes code within packages/svelte/src, add a changeset (npx changeset).

Tests and linting

  • Run the tests with pnpm test and lint the project with pnpm lint

@changeset-bot
Copy link

changeset-bot bot commented Sep 6, 2025

🦋 Changeset detected

Latest commit: 38a1857

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
svelte Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@svelte-docs-bot
Copy link

@github-actions
Copy link
Contributor

github-actions bot commented Sep 6, 2025

Playground

pnpm add https://pkg.pr.new/svelte@16724

@Rich-Harris
Copy link
Member

I feel a bit weird about adding a less-cryptic error for when matched is empty, but still not erroring at all if there are duplicate keys that don't result in an error. Is there some other proxy, besides matched being empty, for those other cases?

I also realised as a result of this PR that validate_each_keys doesn't always work, because the render_effect could run after the block update — for the test case in this PR, it fails with a is undefined. We could change that by turning the render_effect in validate_each_keys to a block, but maybe it would be better to move the check into reconcile inside an if (DEV) block?

@7nik
Copy link
Contributor Author

7nik commented Sep 11, 2025

Checking other cases requires computations. We cannot even do array.length === state.items.size - to_destroy.length (key duplication often results into a shortened list) because state.items may still contain transiting items from previous runs. Probably the simplest computation is a set of seen keys in the reconcile - validate keys during reconciling. Another place is inside create_item. If we want to add any computation to prod.

7nik and others added 2 commits September 12, 2025 13:08
Co-authored-by: Rich Harris <rich.harris@vercel.com>
Co-authored-by: Rich Harris <rich.harris@vercel.com>
@dummdidumm
Copy link
Member

I vote for merging this. I just ran into this and it's really annoying to debug. Yes it's not going to catch all cases but I'd rather fail with a runtime error that gives me a hint at what goes wrong compared to a cryptic "undefined" runtime error.

@7nik
Copy link
Contributor Author

7nik commented Sep 12, 2025

I tried to move validate_each_keys inside reconcile but some tests failed, and I didn't get time to dig into why.

@7nik
Copy link
Contributor Author

7nik commented Sep 13, 2025

I moved validate_each_keys inside #each's block because, if thrown in reconcile, the error isn't caught by the boundary in async mode. Guess it is because reconcile is called in batch callbacks.

@7nik
Copy link
Contributor Author

7nik commented Sep 13, 2025

Btw, in prod the error isn't caught by boundary. I need help here.

@7nik
Copy link
Contributor Author

7nik commented Sep 14, 2025

Added the error emitting for the non-crashing case.
It doesn't emit the error at hydration in prod, but I guess it's fine.

@7nik
Copy link
Contributor Author

7nik commented Sep 24, 2025

Added ensuring the thrown error is caught by a boundary - is this the right approach?
I removed the tests because DEV is always true and thus we cannot really test the prod checks.
No idea why the TSGo test decided to die on an unrelated file.

@Rich-Harris
Copy link
Member

Interestingly, #16840 works for DEV in user code, but not in Svelte code, which means we still can't add a test for this. Any ideas? If we can't get it to behave then we might be better off reverting #16840

@7nik
Copy link
Contributor Author

7nik commented Jan 29, 2026

Opened #17590

7nik and others added 11 commits January 29, 2026 19:04
* chore: bump playwright

* maybe this will help somehow?

* err whatever

* fix
* Revert "chore: allow testing in production env (#16840)"

This reverts commit ffd65e9.

* new approach
* fix: handle renderer run rejections

* add test

* changeset

* simplify

* explanatory comment

---------

Co-authored-by: Antonio Bennett <abennett@mabelslabels.com>
Co-authored-by: Rich Harris <rich.harris@vercel.com>
* fix: only create async functions in SSR output when necessary

* actually...

* simplify generated code a bit more

* simplify
…tent (#17587)

* fix: merge consecutive text nodes during hydration for large text content

Fixes #17582

Browsers automatically split text nodes exceeding 65536 characters into
multiple consecutive text nodes during HTML parsing. This causes hydration
mismatches when Svelte expects a single text node.

The fix merges consecutive text nodes during hydration by:
- Detecting when the current node is a text node
- Finding all consecutive text node siblings
- Merging their content into the first text node
- Removing the extra text nodes

This restores correct hydration behavior for large text content.

* add test, fix

* fix

* fix

* changeset

---------

Co-authored-by: Miner <miner@example.com>
Co-authored-by: Rich Harris <rich.harris@vercel.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This reverts commit 65f77ef.
Copy link
Member

@Rich-Harris Rich-Harris left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

eventually figured out all we needed was a length > keys.size check in the block effect

@7nik
Copy link
Contributor Author

7nik commented Feb 4, 2026

Oh, I missed that keys was added by the refactoring. Good catch!

@7nik 7nik merged commit d7a8e3d into main Feb 4, 2026
18 checks passed
@7nik 7nik deleted the fix-15339 branch February 4, 2026 19:51
@github-actions github-actions bot mentioned this pull request Feb 4, 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.

Cannot read properties of undefined (reading 'prev')

6 participants