[BUGFIX] Regression [Ember 5.12+] Non helpful error when the function for on modifier was forgot as param#21108
[BUGFIX] Regression [Ember 5.12+] Non helpful error when the function for on modifier was forgot as param#21108johanrd wants to merge 6 commits intoemberjs:mainfrom
Conversation
Estimated Asset SizesDiff --- 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
|
674a781 to
680a063
Compare
|
Is the problem still present an canary? Because: #21091 |
|
@NullVoxPopuli yes, as I understand it, this needs to be tested in smoke tests to fully emulate the user dev mode? on 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 ... }. |
|
|
||
| if (DEBUG && !arg0) { | ||
| throw new Error( | ||
| 'You must pass a valid DOM event name as the first argument to the `on` modifier' |
There was a problem hiding this comment.
Should we say what was received instead? Can we provide even more information in the error? maybe the element tag name? (at least since it's kinda hard right now to find what element a modifier is on rn)
There was a problem hiding this comment.
yes, good idea.
Sentry reports something like button.font-bold.hover:bg-white.focus-m-1[type="submit"]
Even better would maybe be to use element.cloneNode(false).outerHTML which would print the whole node as in the dom, like <button type="submit" class="font-bold hover:bg-white" id="save">
It may be too long, but that may not be an issue?
There was a problem hiding this comment.
how does sentry get that?
I do think it would b e too long to include the HTML
There was a problem hiding this comment.
heh, checked now, Sentry's _htmlElementAsString builds a compact CSS-selector-style representation: button#save.btn.primary[type="submit"]. See their implementation: https://github.com/getsentry/sentry-javascript/blob/b3d336c98ee58f124004debf2e6aca60365d15b4/packages/core/src/utils/browser.ts#L68-L122
It is quite complex, though. element.cloneNode(false).outerHTML is simpler and gives the full opening tag from the DOM, but it can get verbose with data attributes, analytics attributes etc. But is that an issue in dev mode? alternatively substring it.
There was a problem hiding this comment.
how are they getting access to the element at all tho? 🤔
There was a problem hiding this comment.
Including html is questionable -- you don't want to leak any data from an app into an exception
There was a problem hiding this comment.
@kategengler ok, yes. something like this would be safe i guess:
You must pass a valid DOM event name as the first argument to the `on` modifier,
but you passed undefined. Usage example: {{on "click" this.handleClick}}. (Element: <button>)
Adding the id and/or the class list would sometimes be helpful, but potentially leaking.
There was a problem hiding this comment.
pushed an update now with the tag name
There was a problem hiding this comment.
I think the classlist is probably fine. Sentry doesn't hide the classes.
There was a problem hiding this comment.
okay, added the id and class list now in css selector / sentry style: button#save.btn.primary
… for on modifier was forget to add emberjs#21045 emberjs#20783
…odifier. + Cleanup redundant test from 5b6f80b
…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.
788bea1 to
dddb309
Compare
… classList, like button#my-id.class1.class2
|
|
||
| }); | ||
| `, | ||
| 'on-modifier-error-test.gjs': ` |
There was a problem hiding this comment.
one of these tests should probably include the selector text, ya?
There was a problem hiding this comment.
yes, good point,
I added it as its own test now: 4bfdd86
Fixes #20783 / #21045
Since Ember 5.12, passing a non-function to the
{{on}}modifier produces an unhelpfulTypeError: 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
Cowritten by Claude.
Not sure whether it should be backported to LTS, considering the repo-merge.