Skip to content

[BUGFIX] Regression [Ember 5.12+] Non helpful error when the function for on modifier was forgot as param#21108

Merged
NullVoxPopuli merged 6 commits intoemberjs:mainfrom
johanrd:fix/20783
Mar 26, 2026
Merged

[BUGFIX] Regression [Ember 5.12+] Non helpful error when the function for on modifier was forgot as param#21108
NullVoxPopuli merged 6 commits intoemberjs:mainfrom
johanrd:fix/20783

Conversation

@johanrd
Copy link
Copy Markdown
Contributor

@johanrd johanrd commented Feb 21, 2026

Fixes #20783 / #21045

Since Ember 5.12, passing a non-function to the {{on}} modifier produces an unhelpful TypeError: Cannot read properties of undefined (reading 'bind') instead of the previous helpful message: "You must pass a function as the second argument to the on modifier; you passed undefined."

Root cause

The glimmer-vm refactor in glimmerjs/glimmer-vm@2d9fc01 replaced expect() (a runtime check that always executes) with localAssert() (guarded by LOCAL_DEBUG, which is stripped in published builds). This meant the callback validation became a no-op in published ember-source, while the .bind() call further down — guarded by DEBUG — still runs, producing the unhelpful TypeError.

The key distinction: LOCAL_DEBUG is only true when developing the ember.js repo itself. DEBUG (from @glimmer/env) is true in user app development mode. The existing test suite always runs with LOCAL_DEBUG=true, so this gap was never caught.

Fix

  • Replace localAssert() with an explicit if (DEBUG) check, matching the pattern already used in the same function for positional argument validation
  • Add a smoke test that runs against built ember-source (LOCAL_DEBUG=false, DEBUG=true) — the exact environment users have — to prevent this class of regression

Cowritten by Claude.

Not sure whether it should be backported to LTS, considering the repo-merge.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Feb 21, 2026

Estimated Asset Sizes

Diff

--- main/out.txt	2026-02-17 19:37:18.000000000 +0000
+++ pr/./pr-22260873684/out.txt	2026-02-21 17:14:28.000000000 +0000
@@ -1,62 +1,62 @@
-╔═══════╤═══════════╤═══════════╗
-║       │ Min       │ Gzip      ║
-╟───────┼───────────┼───────────╢
-║ Total │ 351.99 KB │ 203.84 KB ║
-╚═══════╧═══════════╧═══════════╝
+╔═══════╤═══════════╤══════════╗
+║       │ Min       │ Gzip     ║
+╟───────┼───────────┼──────────╢
+║ Total │ 351.99 KB │ 203.7 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     ║
-╚══════════════════════╧═══════════╧═══════════╝
+╔══════════════════════╤═══════════╤══════════╗
+║ @ember/*             │ Min       │ Gzip     ║
+╟──────────────────────┼───────────┼──────────╢
+║ Total                │ 313.39 KB │ 181.9 KB ║
+╟──────────────────────┼───────────┼──────────╢
+║ -internals           │ 36.65 KB  │ 26.23 KB ║
+║ application          │ 13.23 KB  │ 8 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   │ 832 B    ║
+║ instrumentation      │ 2.43 KB   │ 1.79 KB  ║
+║ modifier             │ 1.22 KB   │ 963 B    ║
+║ object               │ 35.94 KB  │ 22.16 KB ║
+║ owner                │ 159 B     │ 178 B    ║
+║ renderer             │ 630 B     │ 515 B    ║
+║ routing              │ 59.3 KB   │ 34.14 KB ║
+║ runloop              │ 2.36 KB   │ 1.5 KB   ║
+║ service              │ 1 KB      │ 845 B    ║
+║ template             │ 654 B     │ 530 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  ║
-╚═════════════════╧══════════╧══════════╝
+╔═════════════════╤══════════╤═════════╗
+║ @glimmer/*      │ Min      │ Gzip    ║
+╟─────────────────┼──────────┼─────────╢
+║ Total           │ 38.6 KB  │ 21.8 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    │ 246 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.2 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 ║
+╚═════════════════╧══════════╧═════════╝
 

Details

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

╔══════════════════════╤═══════════╤══════════╗
║ @ember/*             │ Min       │ Gzip     ║
╟──────────────────────┼───────────┼──────────╢
║ Total                │ 313.39 KB │ 181.9 KB ║
╟──────────────────────┼───────────┼──────────╢
║ -internals           │ 36.65 KB  │ 26.23 KB ║
║ application          │ 13.23 KB  │ 8 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   │ 832 B    ║
║ instrumentation      │ 2.43 KB   │ 1.79 KB  ║
║ modifier             │ 1.22 KB   │ 963 B    ║
║ object               │ 35.94 KB  │ 22.16 KB ║
║ owner                │ 159 B     │ 178 B    ║
║ renderer             │ 630 B     │ 515 B    ║
║ routing              │ 59.3 KB   │ 34.14 KB ║
║ runloop              │ 2.36 KB   │ 1.5 KB   ║
║ service              │ 1 KB      │ 845 B    ║
║ template             │ 654 B     │ 530 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.8 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    │ 246 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.2 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  ║
╚═════════════════╧══════════╧══════════╝

@johanrd johanrd force-pushed the fix/20783 branch 2 times, most recently from 674a781 to 680a063 Compare February 21, 2026 12:11
@NullVoxPopuli
Copy link
Copy Markdown
Contributor

Is the problem still present an canary?

Because: #21091

@johanrd
Copy link
Copy Markdown
Contributor Author

johanrd commented Feb 21, 2026

@NullVoxPopuli yes, as I understand it, this needs to be tested in smoke tests to fully emulate the user dev mode?

on main(canary), the smoke tests in this PR #21108 (which run with LOCAL_DEBUG=false, DEBUG=true, matching real user dev mode) confirm this. On main/canary:

  not ok 8 - on modifier | error handling: throws helpful error when callback is missing                                                                                                                                                      
      message: Expected helpful error message, got: Cannot read properties of undefined (reading 'bind')                                                                                                                                      
                                                                                                                                                                                                                                              
  not ok 9 - on modifier | error handling: throws helpful error when event name is missing                                                                                                                                                    
      message: Expected helpful error message, got: Cannot destructure property 'tag' of 'ref' as it is undefined.

PR #21091 improved error messages inside check() and localAssert(), but both are gated by LOCAL_DEBUG (not DEBUG), so they're no-ops in published builds. Users still get unhelpful TypeErrors. The fix in fix/20783 correctly replaces localAssert() with if (DEBUG) { throw ... }.

Comment thread packages/@glimmer/runtime/lib/modifiers/on.ts
Comment thread packages/@glimmer/runtime/lib/modifiers/on.ts Outdated
Comment thread packages/@glimmer/runtime/lib/modifiers/on.ts Outdated
NullVoxPopuli
NullVoxPopuli previously approved these changes Mar 7, 2026
@johanrd johanrd force-pushed the fix/20783 branch 4 times, most recently from dddb309 to 871db22 Compare March 7, 2026 18:32
Comment thread smoke-tests/scenarios/basic-test.ts
NullVoxPopuli
NullVoxPopuli previously approved these changes Mar 7, 2026
@NullVoxPopuli
Copy link
Copy Markdown
Contributor

@johanrd I forgot to merge this :( any chance you'd be willing to rebase, and one more time show the error message(s) before and after?

johanrd added 6 commits March 26, 2026 17:09
…e? so that way we aren't defining two variables that have the same value?
Show which element the {{on}} modifier is attached to, helping locate
the issue when modifiers are forwarded via ...attributes.
@johanrd
Copy link
Copy Markdown
Contributor Author

johanrd commented Mar 26, 2026

@NullVoxPopuli Rebased now. See current CI for passing tests, and here for failing tests without the fix, e.g:

not ok 9 Chrome 145.0 - [36 ms] - on modifier | error handling: throws helpful error when callback is missing
        ---
            actual: >
                false
            expected: >
                true
            stack: >
                    at http://localhost:7357/assets/tests-DSd2Dm9s.js:10690:18
            message: >
                Expected helpful error message, got: Cannot read properties of undefined (reading 'bind')
            negative: >
                false
            browser log: |
        ...
    not ok 10 Chrome 145.0 - [52 ms] - on modifier | error handling: throws helpful error when event name is missing
        ---
            actual: >
                false
            expected: >
                true
            stack: >
                    at http://localhost:7357/assets/tests-DSd2Dm9s.js:10710:18
            message: >
                Expected helpful error message, got: Cannot destructure property 'tag' of 'ref' as it is undefined.
            negative: >
                false
            browser log: |
        ...
    not ok 11 Chrome 145.0 - [35 ms] - on modifier | error handling: error message includes element selector
        ---
            actual: >
                false
            expected: >
                true
            stack: >
                    at http://localhost:7357/assets/tests-DSd2Dm9s.js:10730:18
            message: >
                Expected element selector in error, got: Cannot read properties of undefined (reading 'bind')
            negative: >
                false
            browser log: |
        ...

@NullVoxPopuli NullVoxPopuli merged commit f9c4357 into emberjs:main Mar 26, 2026
73 of 74 checks passed
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.

[5.12] Non helpful error when the function for on modifier was forget to add

3 participants