{"record":{"id":"0302d6dc066fba18","repo":"honojs/hono","slug":"event-handler-for-key-is-not-a-function","errorCode":null,"errorMessage":"Event handler for \"${key}\" is not a function","messagePattern":"Event handler for \"(.+?)\" is not a function","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/jsx/dom/render.ts","lineNumber":182,"sourceCode":"const applyProps = (\n  container: SupportedElement,\n  attributes: Props,\n  oldAttributes?: Props\n): void => {\n  attributes ||= {}\n  for (let key in attributes) {\n    const value = attributes[key]\n    if (key !== 'children' && (!oldAttributes || oldAttributes[key] !== value)) {\n      key = normalizeIntrinsicElementKey(key)\n      const eventSpec = getEventSpec(key)\n      if (eventSpec) {\n        if (oldAttributes?.[key] !== value) {\n          if (oldAttributes) {\n            container.removeEventListener(eventSpec[0], oldAttributes[key], eventSpec[1])\n          }\n          if (value != null) {\n            if (typeof value !== 'function') {\n              throw new Error(`Event handler for \"${key}\" is not a function`)\n            }\n            container.addEventListener(eventSpec[0], value, eventSpec[1])\n          }\n        }\n      } else if (key === 'dangerouslySetInnerHTML' && value) {\n        container.innerHTML = value.__html\n      } else if (key === 'ref') {\n        refCleanupMap.get(container)?.()\n        let cleanup\n        if (typeof value === 'function') {\n          cleanup = value(container) || (() => value(null))\n        } else if (value && 'current' in value) {\n          value.current = container\n          cleanup = () => (value.current = null)\n        }\n        refCleanupMap.set(container, cleanup)\n      } else if (key === 'style') {\n        const style = container.style","sourceCodeStart":164,"sourceCodeEnd":200,"githubUrl":"https://github.com/honojs/hono/blob/e2740d5a1bd0b4254e517e3af8b60789284bc7bd/src/jsx/dom/render.ts#L164-L200","documentation":"When hono/jsx/dom applies event-handler props (names starting with 'on') to DOM nodes, the value must be a function so it can be registered with addEventListener. If the prop is defined, non-null, and not a function, applyProps throws during render/diffing.","triggerScenarios":"Passing a non-function to an on* prop: `<button onClick={'clicked'}>`, `<div onMouseEnter={flag && handler}>` where the expression evaluates to a truthy non-function, or spreading an object with an on* key whose value is a string/number.","commonSituations":"Passing the result of invoking a handler instead of the reference (`onClick={handleClick()}`); conditional handlers using `||`/`&&` that leak truthy non-function values; spreading arbitrary props objects onto DOM elements; data mistakenly placed under an on* key.","solutions":["Pass the function reference, not its return value: `onClick={handleClick}`","Fix conditional handlers to resolve to a function or undefined/null (`onClick={enabled ? handler : undefined}`)","When spreading props, filter out or correct any on* keys that hold non-function values"],"exampleFix":"// before\n<button onClick={handleClick()}>Save</button>\n// or\n<button onClick={mode === 'edit' && 'handleSave'}>Save</button>\n// after\n<button onClick={handleClick}>Save</button>\n// or\n<button onClick={mode === 'edit' ? handleSave : undefined}>Save</button>","handlingStrategy":"type-guard","validationCode":"const handler = typeof props.onClick === 'function' ? props.onClick : undefined\n<button onClick={handler}>Save</button>","typeGuard":"const isEventHandler = (v: unknown): v is (e: Event) => void => typeof v === 'function'","tryCatchPattern":"null","preventionTips":["Pass handler references, never invocations","Make conditional handlers resolve to a function or undefined","Sanitize spread props so on* keys are functions or absent"],"tags":["hono","jsx","dom","event-handlers","props"],"backgroundTag":"invalid-event-handler-prop","analyzedSha":"e2740d5a1bd0b4254e517e3af8b60789284bc7bd","analyzedAt":"2026-08-28T10:18:08.750Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}