NativeScript/NativeScript · error · TypeError

Illegal invocation

Error message

Illegal invocation

What it means

MediaQueryList methods (media, matches, addEventListener, removeEventListener, addListener, removeListener, onchange) throw TypeError('Illegal invocation') when called without a proper `this` - i.e. the method was detached from its instance (same as DOM 'Illegal invocation' errors). _throwInvocationError() is a shared helper enforcing that these methods are invoked on a real MediaQueryList instance created by matchMedia().

Source

Thrown at packages/core/media-query-list/index.ts:201

	}

	public set onchange(callback: (this: MediaQueryList, ev: MediaQueryListEvent) => any) {
		this._throwInvocationError?.();

		// Remove old listener if any
		if (this._onChange) {
			this.removeListener(this._onChange);
		}

		if (callback) {
			this.addListener(callback);
		}

		this._onChange = callback;
	}

	private _throwInvocationError() {
		throw new TypeError('Illegal invocation');
	}
}

export { matchMedia, MediaQueryListImpl as MediaQueryList, checkIfMediaQueryMatches };

View on GitHub (pinned to 6800aefa65)

Solutions

  1. Keep the MediaQueryList instance and call methods on it: mql.matches, mql.addListener(cb).
  2. Bind methods: mql.addListener.bind(mql) before detaching.
  3. Wrap in an arrow function when passing as callback: () => mql.matches.
  4. Use mql.addEventListener('change', cb) on the instance instead of extracting handlers.

Example fix

// before
const { matches } = matchMedia('(min-width: 600px)');
console.log(matches);
// after
const mql = matchMedia('(min-width: 600px)');
console.log(mql.matches);
Defensive patterns

Strategy: type-guard

Validate before calling

const mql = matchMedia('(min-width: 500px)');
// keep a reference; never destructure methods off mql

Type guard

function isBoundMql(m) {
  return m instanceof Object && typeof m.media === 'string' && typeof m.matches === 'boolean';
}

Try / catch

try {
  matches = detachedFn();
} catch (e) {
  if (e instanceof TypeError && e.message === 'Illegal invocation') {
    matches = mql.matches; // call on the instance
  } else throw e;
}

Prevention

When it happens

Trigger: Destructuring methods off the instance (`const { matches, addListener } = matchMedia(q)`) then calling them bare; passing the method as a standalone callback (matches.call(undefined)); assigning the method to another object and calling it.

Common situations: React/Vue code extracting mql.matches into a variable for reactivity; functional-style code passing mql.addEventListener as a free function; mocks in unit tests that copy methods onto plain objects.

Related errors


AI-assisted analysis of NativeScript/NativeScript@6800aefa65 (2026-08-30). Data as JSON: /api/errors/617a19353778900f. Report an issue: GitHub.