{"record":{"id":"144ae5e5349ff10d","repo":"emberjs/ember.js","slug":"you-can-only-once-passive-or-capture-named","errorCode":null,"errorMessage":"You can only `once`, `passive` or `capture` named arguments to the `on` modifier, but you provided ${Object.keys(extra).join(', ')} on ${selector}","messagePattern":"You can only `once`, `passive` or `capture` named arguments to the `on` modifier, but you provided (.+?) on (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/@glimmer/runtime/lib/modifiers/on.ts","lineNumber":138,"sourceCode":"        }`;\n      });\n\n      passive = check(_passive, CheckOr(CheckBoolean, CheckUndefined), (actual) => {\n        return `You must pass a boolean or undefined as the \\`passive\\` argument to the \\`on\\` modifier; you passed ${actual}. While rendering:\\n\\n${\n          // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- @fixme\n          args.named['passive']!.debugLabel ?? `{unlabeled value}`\n        }`;\n      });\n\n      capture = check(_capture, CheckOr(CheckBoolean, CheckUndefined), (actual) => {\n        return `You must pass a boolean or undefined as the \\`capture\\` argument to the \\`on\\` modifier; you passed ${actual}. While rendering:\\n\\n${\n          // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- @fixme\n          args.named['capture']!.debugLabel ?? `{unlabeled value}`\n        }`;\n      });\n\n      if (Object.keys(extra).length > 0) {\n        throw new Error(\n          `You can only \\`once\\`, \\`passive\\` or \\`capture\\` named arguments to the \\`on\\` modifier, but you provided ${Object.keys(\n            extra\n          ).join(', ')} on ${selector}`\n        );\n      }\n    } else {\n      let { once: _once, passive: _passive, capture: _capture } = args.named;\n\n      if (_once) {\n        once = valueForRef(_once) as boolean | undefined;\n      }\n\n      if (_passive) {\n        passive = valueForRef(_passive) as boolean | undefined;\n      }\n\n      if (_capture) {\n        capture = valueForRef(_capture) as boolean | undefined;","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/emberjs/ember.js/blob/26f97246a8bf2e28edf26ac3093da2e86c04ffc5/packages/@glimmer/runtime/lib/modifiers/on.ts#L120-L156","documentation":"The `on` element modifier only accepts three named options: `once`, `passive`, and `capture`, all booleans. During render (in DEBUG builds), updateListener reifies the named args and throws if any other named key is present, listing the offending key names and the element's selector.","triggerScenarios":"Calling the `on` modifier in a template with any named argument other than once/passive/capture, e.g. {{on \"click\" this.handler stopPropagation=true}} or a typo like {{on \"click\" this.haner onces=true}}. Thrown at install or update of the modifier.","commonSituations":"Migrating from other event-handling patterns where users expect options like `preventDefault` or `debounce`; typos in option names; passing extra data as named args instead of using the `fn` helper.","solutions":["Remove the unsupported named argument from the `on` modifier usage.","If it was a typo, correct it to one of `once`, `passive`, or `capture`.","If you need to pass extra data to the handler, wrap the callback with the `fn` helper: {{on \"click\" (fn this.handler arg)}}.","Handle behaviors like preventDefault inside the callback body, not as a modifier option."],"exampleFix":"<!-- before -->\n<button {{on \"click\" this.save preventDefault=true}}>Save</button>\n\n<!-- after -->\n<button {{on \"click\" this.save}}>Save</button>\n\n// this.save\nsave(event) {\n  event.preventDefault();\n  // ...\n}","handlingStrategy":"validation","validationCode":"const ALLOWED = ['once', 'passive', 'capture'];\nfunction checkOnOptions(named = {}) {\n  const extra = Object.keys(named).filter((k) => !ALLOWED.includes(k));\n  if (extra.length) throw new Error(`Invalid 'on' modifier options: ${extra.join(', ')}`);\n}\n// template lint rule alternative:\n// {{on \"click\" this.handler once=true}} -> validate named args before render","typeGuard":"function isOnModifierOptions(v) {\n  return v != null && Object.keys(v).every((k) => ['once', 'passive', 'capture'].includes(k));\n}","tryCatchPattern":null,"preventionTips":["Only ever pass once/passive/capture as named args to {{on}}.","Use {{fn}} for extra handler arguments, never extra named args.","Add an eslint-plugin-ember/template lint to flag unknown modifier args.","Review on-modifier usages when migrating from classic event handling."],"tags":["ember","glimmer","modifier","template","developer-error"],"backgroundTag":"invalid-modifier-argument","analyzedSha":"26f97246a8bf2e28edf26ac3093da2e86c04ffc5","analyzedAt":"2026-09-01T05:01:28.182Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}