appsmithorg/appsmith · error · Error

onModelChange expects a function as parameter

Error message

onModelChange expects a function as parameter

What it means

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.

Source

Thrown at app/client/src/widgets/CustomWidget/component/customWidgetscript.js:242

          if (typeof fn !== "function") {
            throw new Error("onUiChange expects a function as parameter");
          }

          uiSubscribers.push(fn);
          fn(window.appsmith.ui);

          return () => {
            // Unsubscribe from UI changes
            const index = uiSubscribers.indexOf(fn);

            if (index > -1) {
              uiSubscribers.splice(index, 1);
            }
          };
        },
        onModelChange: (fn) => {
          if (typeof fn !== "function") {
            throw new Error("onModelChange expects a function as parameter");
          }

          modelSubscribers.push(fn);
          fn(window.appsmith.model);

          return () => {
            // Unsubscribe from model changes
            const index = modelSubscribers.indexOf(fn);

            if (index > -1) {
              modelSubscribers.splice(index, 1);
            }
          };
        },
        updateModel: (obj) => {
          if (!obj || typeof obj !== "object") {
            throw new Error("updateModel expects an object as parameter");
          }

View on GitHub (pinned to 8cd9021c24)

Solutions

  1. Pass a function reference directly: appsmith.onModelChange(handleChange) where handleChange is a hoisted function or an initialized const arrow.
  2. If using an inline handler, pass the arrow itself: appsmith.onModelChange((model) => { ... }).
  3. Check for undefined before registering if the handler is optional: if (typeof handler === 'function') appsmith.onModelChange(handler).
  4. Store the returned unsubscribe function and call it on cleanup to avoid duplicate subscriptions.

Example fix

// before
appsmith.onModelChange(handleChange()); // invokes handleChange, passes its (undefined) return

// after
appsmith.onModelChange(handleChange); // passes the function reference itself
Defensive patterns

Strategy: type-guard

Validate before calling

// Before registering, confirm fn is callable
if (typeof handler !== 'function') {
  throw new TypeError('onModelChange handler must be a function, got ' + typeof handler);
}
const unsubscribe = appsmith.onModelChange(handler);

Type guard

const isCallable = (v) => typeof v === 'function';

// usage
if (isCallable(handleChange)) {
  appsmith.onModelChange(handleChange);
}

Try / catch

try {
  const off = appsmith.onModelChange(handleChange);
} catch (e) {
  console.error('onModelChange registration failed:', e.message);
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of appsmithorg/appsmith@8cd9021c24 (2026-08-12). Data as JSON: /api/errors/6d1c6da5fa202ccd. Report an issue: GitHub.