{"record":{"id":"6d1c6da5fa202ccd","repo":"appsmithorg/appsmith","slug":"onmodelchange-expects-a-function-as-parameter","errorCode":null,"errorMessage":"onModelChange expects a function as parameter","messagePattern":"onModelChange expects a function as parameter","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"app/client/src/widgets/CustomWidget/component/customWidgetscript.js","lineNumber":242,"sourceCode":"          if (typeof fn !== \"function\") {\n            throw new Error(\"onUiChange expects a function as parameter\");\n          }\n\n          uiSubscribers.push(fn);\n          fn(window.appsmith.ui);\n\n          return () => {\n            // Unsubscribe from UI changes\n            const index = uiSubscribers.indexOf(fn);\n\n            if (index > -1) {\n              uiSubscribers.splice(index, 1);\n            }\n          };\n        },\n        onModelChange: (fn) => {\n          if (typeof fn !== \"function\") {\n            throw new Error(\"onModelChange expects a function as parameter\");\n          }\n\n          modelSubscribers.push(fn);\n          fn(window.appsmith.model);\n\n          return () => {\n            // Unsubscribe from model changes\n            const index = modelSubscribers.indexOf(fn);\n\n            if (index > -1) {\n              modelSubscribers.splice(index, 1);\n            }\n          };\n        },\n        updateModel: (obj) => {\n          if (!obj || typeof obj !== \"object\") {\n            throw new Error(\"updateModel expects an object as parameter\");\n          }","sourceCodeStart":224,"sourceCodeEnd":260,"githubUrl":"https://github.com/appsmithorg/appsmith/blob/8cd9021c24cdbea1c3c12c966073708e83db60c2/app/client/src/widgets/CustomWidget/component/customWidgetscript.js#L224-L260","documentation":"Thrown by window.appsmith.onModelChange() inside a legacy Custom Widget's iframe sandbox. The method registers a subscriber that is invoked whenever the widget's model (the JSON object exchanged with the parent Appsmith app) changes; it also calls the callback immediately with the current model. It refuses any argument that is not a function because it must later invoke fn(window.appsmith.model) and push fn into modelSubscribers.","triggerScenarios":"Calling appsmith.onModelChange(undefined), appsmith.onModelChange(null), appsmith.onModelChange({handleChange:...}), or appsmith.onModelChange('handleChange') from the iframe's script. Also triggered by passing the result of a void expression, e.g. appsmith.onModelChange(someFn()) where someFn returns undefined.","commonSituations":"Refactoring iframe code and forgetting to pass the callback; referencing an undefined helper; copy-pasting from a sample that used a named function declaration that was later renamed; passing an arrow assigned to a const that lives in a different scope and resolved to undefined at call time.","solutions":["Pass a function reference directly: appsmith.onModelChange(handleChange) where handleChange is a hoisted function or an initialized const arrow.","If using an inline handler, pass the arrow itself: appsmith.onModelChange((model) => { ... }).","Check for undefined before registering if the handler is optional: if (typeof handler === 'function') appsmith.onModelChange(handler).","Store the returned unsubscribe function and call it on cleanup to avoid duplicate subscriptions."],"exampleFix":"// before\nappsmith.onModelChange(handleChange()); // invokes handleChange, passes its (undefined) return\n\n// after\nappsmith.onModelChange(handleChange); // passes the function reference itself","handlingStrategy":"type-guard","validationCode":"// Before registering, confirm fn is callable\nif (typeof handler !== 'function') {\n  throw new TypeError('onModelChange handler must be a function, got ' + typeof handler);\n}\nconst unsubscribe = appsmith.onModelChange(handler);","typeGuard":"const isCallable = (v) => typeof v === 'function';\n\n// usage\nif (isCallable(handleChange)) {\n  appsmith.onModelChange(handleChange);\n}","tryCatchPattern":"try {\n  const off = appsmith.onModelChange(handleChange);\n} catch (e) {\n  console.error('onModelChange registration failed:', e.message);\n}","preventionTips":["Always pass a function reference, never the result of invoking it.","Lint for appsmith.onModelChange(\\w+\\(\\)) patterns where the handler is invoked instead of passed.","Hoist named handler functions so they are defined before the onModelChange call.","Keep the returned unsubscribe function and call it on iframe teardown."],"tags":["custom-widget","appsmith-api","parameter-validation","javascript"],"backgroundTag":null,"analyzedSha":"8cd9021c24cdbea1c3c12c966073708e83db60c2","analyzedAt":"2026-08-12T22:14:19.293Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}