greensock/GSAP · warning

Element not found: ${t}

Error message

Element not found: ${t}

What it means

Observer's _getTarget helper resolves the `target` config to a DOM element via gsap.utils.toArray. When the selector/element cannot be resolved it warns "Element not found: <t>" and returns null (which makes Observer fall back to the document element in init). This library throws it so you know your selector matched nothing rather than silently observing the wrong element.

Source

Thrown at src/Observer.js:57

			if (value || value === 0) {
				_startup && (_win.history.scrollRestoration = "manual"); // otherwise the new position will get overwritten by the browser onload.
				let isNormalizing = _normalizer && _normalizer.isPressed;
				value = cachingFunc.v = Math.round(value) || (_normalizer && _normalizer.iOS ? 1 : 0); //TODO: iOS Bug: if you allow it to go to 0, Safari can start to report super strange (wildly inaccurate) touch positions!
				f(value);
				cachingFunc.cacheID = _scrollers.cache;
				isNormalizing && _bridge("ss", value); // set scroll (notify ScrollTrigger so it can dispatch a "scrollStart" event if necessary
			} else if (doNotCache || _scrollers.cache !== cachingFunc.cacheID || _bridge("ref")) {
				cachingFunc.cacheID = _scrollers.cache;
				cachingFunc.v = f();
			}
			return cachingFunc.v + cachingFunc.offset;
		};
		cachingFunc.offset = 0;
		return f && cachingFunc;
	},
	_horizontal = {s: _scrollLeft, p: "left", p2: "Left", os: "right", os2: "Right", d: "width", d2: "Width", a: "x", sc: _scrollCacheFunc(function(value) { return arguments.length ? _win.scrollTo(value, _vertical.sc()) : _win.pageXOffset || _doc[_scrollLeft] || _docEl[_scrollLeft] || _body[_scrollLeft] || 0})},
	_vertical = {s: _scrollTop, p: "top", p2: "Top", os: "bottom", os2: "Bottom", d: "height", d2: "Height", a: "y", op: _horizontal, sc: _scrollCacheFunc(function(value) { return arguments.length ? _win.scrollTo(_horizontal.sc(), value) : _win.pageYOffset || _doc[_scrollTop] || _docEl[_scrollTop] || _body[_scrollTop] || 0})},
	_getTarget = (t, self) => ((self && self._ctx && self._ctx.selector) || gsap.utils.toArray)(t)[0] || (typeof(t) === "string" && gsap.config().nullTargetWarn !== false ? console.warn("Element not found:", t) : null),

	_isWithin = (element, list) => { // check if the element is in the list or is a descendant of an element in the list.
		let i = list.length;
		while (i--) {
			if (list[i] === element || list[i].contains(element)) {
				return true;
			}
		}
		return false;
	},
	_getScrollFunc = (element, {s, sc}) => { // we store the scroller functions in an alternating sequenced Array like [element, verticalScrollFunc, horizontalScrollFunc, ...] so that we can minimize memory, maximize performance, and we also record the last position as a ".rec" property in order to revert to that after refreshing to ensure things don't shift around.
		_isViewport(element) && (element = _doc.scrollingElement || _docEl);
		let i = _scrollers.indexOf(element),
			offset = sc === _vertical.sc ? 1 : 2;
		!~i && (i = _scrollers.push(element) - 1);
		_scrollers[i + offset] || _addListener(element, "scroll", _onScroll); // clear the cache when a scroll occurs
		let prev = _scrollers[i + offset],
			func = prev || (_scrollers[i + offset] = _scrollCacheFunc(_getProxyProp(element, s), true) || (_isViewport(element) ? sc : _scrollCacheFunc(function(value) { return arguments.length ? (element[s] = value) : element[s]; })));

View on GitHub (pinned to 13e2b79054)

Solutions

  1. Ensure the target element exists in the DOM before creating the Observer (wrap in DOMContentLoaded or run after framework mount)
  2. Fix the selector string or pass an actual Element reference instead of a string
  3. Set gsap.config({nullTargetWarn: false}) only if a missing target is expected and falling back to the document element is acceptable
  4. Verify you are querying the correct document/iframe context

Example fix

// before
Observer.create({ target: '#scroller', onY: y => console.log(y) });
// after
document.addEventListener('DOMContentLoaded', () => {
  const el = document.querySelector('#scroller');
  if (el) Observer.create({ target: el, onY: y => console.log(y) });
});
Defensive patterns

Strategy: validation

Validate before calling

const el = typeof target === 'string' ? document.querySelector(target) : target;
if (!(el instanceof Element)) { throw new Error(`Observer target not found: ${target}`); }
new Observer({ target: el });

Type guard

function isElement(v) { return v instanceof Element; }

Prevention

When it happens

Trigger: new Observer({target: "#missing"}) or Observer.create({target: ...}) where the selector string matches no element, the element is not yet in the DOM, or a null/undefined target is passed before the DOM is ready.

Common situations: Running before DOMContentLoaded, typos in the selector, targeting elements rendered later by a framework (React/Vue mounts), or passing a selector scoped to a different document/iframe.

Related errors


AI-assisted analysis of greensock/GSAP@13e2b79054 (2026-08-29). Data as JSON: /api/errors/b10052e85fc3e24d. Report an issue: GitHub.