Skip to content

[BUGFIX] Fix {{#each}} runtime crash when array contains null/undefined items with key #20786 - #21124

Merged
NullVoxPopuli merged 2 commits into
emberjs:mainfrom
johanrd:fix/20786
Mar 3, 2026
Merged

[BUGFIX] Fix {{#each}} runtime crash when array contains null/undefined items with key #20786#21124
NullVoxPopuli merged 2 commits into
emberjs:mainfrom
johanrd:fix/20786

Conversation

@johanrd

@johanrd johanrd commented Feb 27, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Fixes {{#each}} throwing Cannot call get with '...' on an undefined object when the iterated array contains null or undefined items and a key is specified (e.g. {{#each items key="id"}})
  • Guards against null/undefined items in keyForPath before calling getPath, returning the item itself as the key

Fixes #20786

Reproduction

https://limber.glimdown.com/edit?c=MYewdgzgLgBAtgTwIICcUEMEwLwwNoCMANDAK5gAmApgGYCWYVFAugFCsA8UVcADgDbpuAPlYwYAbwkBiKumAALeMjSYYAayoJsAIjoUdMdBBgAfOtzimAvtbHjJEiz1v2pAejmLXHd5YFCVMJAA&format=gjs

Test plan

  • Added tests for {{#each}} with undefined and null items in the array when key is specified
  • Verified tests fail without the fix with the exact error from the bug report

Alternatives to this fix

  1. Wire getPath to _getPath instead of get in environment.ts
  2. Remove/relax the assertion in get() for null/undefined

I'd lean toward the current fix because:

  • The get() assertion is intentional for the public API — calling get(undefined, 'foo') is almost always a bug in user code, and the assertion helps catch that
  • _getPath/_getProp being lenient is for internal chained path traversal (e.g. get(obj, 'a.b.c') where a.b is undefined)
  • Fixing in keyForPath is more targeted

Cowritten by Claude

@github-actions

github-actions Bot commented Feb 27, 2026

Copy link
Copy Markdown
Contributor
Estimated Asset Sizes

Diff

--- main/out.txt	2026-03-03 16:45:40.000000000 +0000
+++ pr/./pr-22633693745/out.txt	2026-03-03 16:58:40.000000000 +0000
@@ -1,34 +1,34 @@
 ╔═══════╤═══════════╤═══════════╗
 ║       │ Min       │ Gzip      ║
 ╟───────┼───────────┼───────────╢
-║ Total │ 351.99 KB │ 203.84 KB ║
+║ Total │ 351.99 KB │ 203.77 KB ║
 ╚═══════╧═══════════╧═══════════╝
 
 ╔══════════════════════╤═══════════╤═══════════╗
 ║ @ember/*             │ Min       │ Gzip      ║
 ╟──────────────────────┼───────────┼───────────╢
-║ Total                │ 313.39 KB │ 181.91 KB ║
+║ Total                │ 313.39 KB │ 182.01 KB ║
 ╟──────────────────────┼───────────┼───────────╢
 ║ -internals           │ 36.65 KB  │ 26.22 KB  ║
-║ application          │ 13.23 KB  │ 8.05 KB   ║
+║ application          │ 13.23 KB  │ 8.08 KB   ║
 ║ array                │ 13.01 KB  │ 7.46 KB   ║
 ║ canary-features      │ 304 B     │ 389 B     ║
-║ component            │ 2.05 KB   │ 1.64 KB   ║
+║ component            │ 2.05 KB   │ 1.61 KB   ║
 ║ controller           │ 1.96 KB   │ 1.41 KB   ║
 ║ debug                │ 11.69 KB  │ 8.12 KB   ║
 ║ deprecated-features  │ 31 B      │ 77 B      ║
 ║ destroyable          │ 561 B     │ 383 B     ║
 ║ enumerable           │ 259 B     │ 387 B     ║
-║ helper               │ 1.08 KB   │ 811 B     ║
+║ helper               │ 1.08 KB   │ 845 B     ║
 ║ instrumentation      │ 2.43 KB   │ 1.79 KB   ║
-║ modifier             │ 1.22 KB   │ 965 B     ║
+║ modifier             │ 1.22 KB   │ 960 B     ║
 ║ object               │ 35.94 KB  │ 22.16 KB  ║
 ║ owner                │ 159 B     │ 178 B     ║
-║ renderer             │ 630 B     │ 487 B     ║
-║ routing              │ 59.3 KB   │ 34.12 KB  ║
+║ renderer             │ 630 B     │ 519 B     ║
+║ routing              │ 59.3 KB   │ 34.14 KB  ║
 ║ runloop              │ 2.36 KB   │ 1.5 KB    ║
 ║ service              │ 1 KB      │ 845 B     ║
-║ template             │ 654 B     │ 541 B     ║
+║ template             │ 654 B     │ 558 B     ║
 ║ template-compilation │ 429 B     │ 366 B     ║
 ║ template-compiler    │ 123.08 KB │ 59.45 KB  ║
 ║ template-factory     │ 370 B     │ 374 B     ║
@@ -40,19 +40,19 @@
 ╔═════════════════╤══════════╤══════════╗
 ║ @glimmer/*      │ Min      │ Gzip     ║
 ╟─────────────────┼──────────┼──────────╢
-║ Total           │ 38.6 KB  │ 21.94 KB ║
+║ Total           │ 38.6 KB  │ 21.75 KB ║
 ╟─────────────────┼──────────┼──────────╢
 ║ destroyable     │ 2.77 KB  │ 1.39 KB  ║
 ║ encoder         │ 81 B     │ 171 B    ║
 ║ env             │ 38 B     │ 87 B     ║
 ║ global-context  │ 886 B    │ 545 B    ║
 ║ manager         │ 977 B    │ 608 B    ║
-║ node            │ 175 B    │ 260 B    ║
+║ node            │ 175 B    │ 243 B    ║
 ║ opcode-compiler │ 1.11 KB  │ 894 B    ║
 ║ owner           │ 159 B    │ 202 B    ║
 ║ program         │ 252 B    │ 301 B    ║
-║ reference       │ 548 B    │ 531 B    ║
-║ runtime         │ 10.32 KB │ 5.32 KB  ║
+║ reference       │ 548 B    │ 509 B    ║
+║ runtime         │ 10.32 KB │ 5.18 KB  ║
 ║ tracking        │ 1.34 KB  │ 1.16 KB  ║
 ║ util            │ 1.94 KB  │ 1.68 KB  ║
 ║ validator       │ 15.75 KB │ 6.96 KB  ║

Details

This PRmain
╔═══════╤═══════════╤═══════════╗
║       │ Min       │ Gzip      ║
╟───────┼───────────┼───────────╢
║ Total │ 351.99 KB │ 203.77 KB ║
╚═══════╧═══════════╧═══════════╝

╔══════════════════════╤═══════════╤═══════════╗
║ @ember/*             │ Min       │ Gzip      ║
╟──────────────────────┼───────────┼───────────╢
║ Total                │ 313.39 KB │ 182.01 KB ║
╟──────────────────────┼───────────┼───────────╢
║ -internals           │ 36.65 KB  │ 26.22 KB  ║
║ application          │ 13.23 KB  │ 8.08 KB   ║
║ array                │ 13.01 KB  │ 7.46 KB   ║
║ canary-features      │ 304 B     │ 389 B     ║
║ component            │ 2.05 KB   │ 1.61 KB   ║
║ controller           │ 1.96 KB   │ 1.41 KB   ║
║ debug                │ 11.69 KB  │ 8.12 KB   ║
║ deprecated-features  │ 31 B      │ 77 B      ║
║ destroyable          │ 561 B     │ 383 B     ║
║ enumerable           │ 259 B     │ 387 B     ║
║ helper               │ 1.08 KB   │ 845 B     ║
║ instrumentation      │ 2.43 KB   │ 1.79 KB   ║
║ modifier             │ 1.22 KB   │ 960 B     ║
║ object               │ 35.94 KB  │ 22.16 KB  ║
║ owner                │ 159 B     │ 178 B     ║
║ renderer             │ 630 B     │ 519 B     ║
║ routing              │ 59.3 KB   │ 34.14 KB  ║
║ runloop              │ 2.36 KB   │ 1.5 KB    ║
║ service              │ 1 KB      │ 845 B     ║
║ template             │ 654 B     │ 558 B     ║
║ template-compilation │ 429 B     │ 366 B     ║
║ template-compiler    │ 123.08 KB │ 59.45 KB  ║
║ template-factory     │ 370 B     │ 374 B     ║
║ test                 │ 923 B     │ 627 B     ║
║ utils                │ 4.11 KB   │ 3.6 KB    ║
║ version              │ 55 B      │ 131 B     ║
╚══════════════════════╧═══════════╧═══════════╝

╔═════════════════╤══════════╤══════════╗
║ @glimmer/*      │ Min      │ Gzip     ║
╟─────────────────┼──────────┼──────────╢
║ Total           │ 38.6 KB  │ 21.75 KB ║
╟─────────────────┼──────────┼──────────╢
║ destroyable     │ 2.77 KB  │ 1.39 KB  ║
║ encoder         │ 81 B     │ 171 B    ║
║ env             │ 38 B     │ 87 B     ║
║ global-context  │ 886 B    │ 545 B    ║
║ manager         │ 977 B    │ 608 B    ║
║ node            │ 175 B    │ 243 B    ║
║ opcode-compiler │ 1.11 KB  │ 894 B    ║
║ owner           │ 159 B    │ 202 B    ║
║ program         │ 252 B    │ 301 B    ║
║ reference       │ 548 B    │ 509 B    ║
║ runtime         │ 10.32 KB │ 5.18 KB  ║
║ tracking        │ 1.34 KB  │ 1.16 KB  ║
║ util            │ 1.94 KB  │ 1.68 KB  ║
║ validator       │ 15.75 KB │ 6.96 KB  ║
║ vm              │ 495 B    │ 569 B    ║
║ wire-format     │ 1.84 KB  │ 1.35 KB  ║
╚═════════════════╧══════════╧══════════╝
╔═══════╤═══════════╤═══════════╗
║       │ Min       │ Gzip      ║
╟───────┼───────────┼───────────╢
║ Total │ 351.99 KB │ 203.84 KB ║
╚═══════╧═══════════╧═══════════╝

╔══════════════════════╤═══════════╤═══════════╗
║ @ember/*             │ Min       │ Gzip      ║
╟──────────────────────┼───────────┼───────────╢
║ Total                │ 313.39 KB │ 181.91 KB ║
╟──────────────────────┼───────────┼───────────╢
║ -internals           │ 36.65 KB  │ 26.22 KB  ║
║ application          │ 13.23 KB  │ 8.05 KB   ║
║ array                │ 13.01 KB  │ 7.46 KB   ║
║ canary-features      │ 304 B     │ 389 B     ║
║ component            │ 2.05 KB   │ 1.64 KB   ║
║ controller           │ 1.96 KB   │ 1.41 KB   ║
║ debug                │ 11.69 KB  │ 8.12 KB   ║
║ deprecated-features  │ 31 B      │ 77 B      ║
║ destroyable          │ 561 B     │ 383 B     ║
║ enumerable           │ 259 B     │ 387 B     ║
║ helper               │ 1.08 KB   │ 811 B     ║
║ instrumentation      │ 2.43 KB   │ 1.79 KB   ║
║ modifier             │ 1.22 KB   │ 965 B     ║
║ object               │ 35.94 KB  │ 22.16 KB  ║
║ owner                │ 159 B     │ 178 B     ║
║ renderer             │ 630 B     │ 487 B     ║
║ routing              │ 59.3 KB   │ 34.12 KB  ║
║ runloop              │ 2.36 KB   │ 1.5 KB    ║
║ service              │ 1 KB      │ 845 B     ║
║ template             │ 654 B     │ 541 B     ║
║ template-compilation │ 429 B     │ 366 B     ║
║ template-compiler    │ 123.08 KB │ 59.45 KB  ║
║ template-factory     │ 370 B     │ 374 B     ║
║ test                 │ 923 B     │ 627 B     ║
║ utils                │ 4.11 KB   │ 3.6 KB    ║
║ version              │ 55 B      │ 131 B     ║
╚══════════════════════╧═══════════╧═══════════╝

╔═════════════════╤══════════╤══════════╗
║ @glimmer/*      │ Min      │ Gzip     ║
╟─────────────────┼──────────┼──────────╢
║ Total           │ 38.6 KB  │ 21.94 KB ║
╟─────────────────┼──────────┼──────────╢
║ destroyable     │ 2.77 KB  │ 1.39 KB  ║
║ encoder         │ 81 B     │ 171 B    ║
║ env             │ 38 B     │ 87 B     ║
║ global-context  │ 886 B    │ 545 B    ║
║ manager         │ 977 B    │ 608 B    ║
║ node            │ 175 B    │ 260 B    ║
║ opcode-compiler │ 1.11 KB  │ 894 B    ║
║ owner           │ 159 B    │ 202 B    ║
║ program         │ 252 B    │ 301 B    ║
║ reference       │ 548 B    │ 531 B    ║
║ runtime         │ 10.32 KB │ 5.32 KB  ║
║ tracking        │ 1.34 KB  │ 1.16 KB  ║
║ util            │ 1.94 KB  │ 1.68 KB  ║
║ validator       │ 15.75 KB │ 6.96 KB  ║
║ vm              │ 495 B    │ 569 B    ║
║ wire-format     │ 1.84 KB  │ 1.35 KB  ║
╚═════════════════╧══════════╧══════════╝

@NullVoxPopuli
NullVoxPopuli merged commit 738b881 into emberjs:main Mar 3, 2026
30 checks passed
@johanrd
johanrd deleted the fix/20786 branch March 7, 2026 12:18
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.

each with an undefined element and key blows up

2 participants