emberjs/ember.js · error · Error

You marked this listener as 'passive', meaning that you must

Error message

You marked this listener as 'passive', meaning that you must not call 'event.preventDefault()': \n\n${userProvidedCallback.name || `{anonymous function}`}

What it means

A listener registered with the `on` modifier was marked `passive=true`, which tells the browser the handler will never call `event.preventDefault()`. In DEBUG builds, updateListener wraps the callback and monkey-patches `event.preventDefault` to throw if the handler calls it anyway, so the developer learns immediately that the passive contract is broken.

Source

Thrown at packages/@glimmer/runtime/lib/modifiers/on.ts:194

    // https://bugs.chromium.org/p/chromium/issues/detail?id=770208
    if (shouldUpdate) {
      if (once !== undefined || passive !== undefined || capture !== undefined) {
        options = { once, passive, capture };
      }
    }

    if (shouldUpdate) {
      let callback = userProvidedCallback;

      if (DEBUG) {
        callback = userProvidedCallback.bind(untouchableContext);

        if (passive) {
          let _callback = callback;

          callback = (event) => {
            event.preventDefault = () => {
              throw new Error(
                `You marked this listener as 'passive', meaning that you must not call 'event.preventDefault()': \n\n${
                  userProvidedCallback.name || `{anonymous function}`
                }`
              );
            };

            return _callback(event);
          };
        }
      }

      this.listener = {
        eventName,
        callback,
        userProvidedCallback,
        once,
        passive,
        capture,

View on GitHub (pinned to 26f97246a8)

Solutions

  1. Remove `event.preventDefault()` from the passive handler's code.
  2. If preventDefault is genuinely needed, drop `passive=true` from the `on` modifier usage.
  3. Split the logic: use a non-passive listener when preventDefault is required, or prevent the default via a different mechanism (e.g. CSS `overflow` handling, `touch-action`).

Example fix

{{!-- before --}}
<div {{on "wheel" this.onWheel passive=true}}>...</div>

// before
onWheel(event) { event.preventDefault(); /* ... */ }

{{!-- after --}}
<div {{on "wheel" this.onWheel}}>...</div>
Defensive patterns

Strategy: validation

Validate before calling

function assertNoPreventDefault(fn) {
  const src = Function.prototype.toString.call(fn);
  if (/preventDefault\s*\(/.test(src)) {
    throw new Error(`${fn.name || 'handler'} calls preventDefault; cannot be passive`);
  }
}
assertNoPreventDefault(this.onWheel); // before registering with passive=true

Try / catch

try {
  handler(event);
} catch (e) {
  if (String(e.message).includes("you must not call 'event.preventDefault()'")) {
    // remove passive=true from the modifier or drop preventDefault in handler
  } else throw e;
}

Prevention

When it happens

Trigger: Using {{on "scroll" this.handler passive=true}} (or similar) and then invoking event.preventDefault() inside this.handler. The wrapped callback throws the moment preventDefault is called on the event object.

Common situations: Scroll/touch/wheel listeners added for performance with `passive` but whose handler conditionally calls preventDefault; copying a handler that previously worked without the passive option.

Related errors


AI-assisted analysis of emberjs/ember.js@26f97246a8 (2026-09-01). Data as JSON: /api/errors/0e23fdde65c4dbd1. Report an issue: GitHub.