SeleniumHQ/selenium · error · Error

Argument to isShown must be of type Element

Error message

Argument to isShown must be of type Element

What it means

The TypeScript port of the isShown atom (is-displayed.ts, compiled to bot.dom.typescript.isShown) mirrors the legacy Closure guard: isShownInternal throws when elem is not an Element. This is the modern, Shadow-DOM-aware visibility atom used by Selenium Manager and newer bindings. The guard exists because the body of the function calls elem.closest('select'), getComputedStyle, getClientRects, and offsetParent — all Element-only APIs — so a non-Element would throw a less informative TypeError deeper in.

Source

Thrown at javascript/atoms/typescript/is-displayed.ts:370

      if ((overflowsX && containerOverflow.x !== 'visible') || (overflowsY && containerOverflow.y !== 'visible')) {
        if (treatAsFixedPosition) {
          var docScroll = getScroll(container);
          if (region.left >= htmlElem.scrollWidth - docScroll.x || region.right >= htmlElem.scrollHeight - docScroll.y) {
            return 'hidden';
          }
        }

        var containerOverflowState = getOverflowState(container);
        return containerOverflowState === 'hidden' ? 'hidden' : 'scroll';
      }
    }

    return 'none';
  }

  function isShownInternal(elem: Element, ignoreOpacity: boolean, displayedFn: (element: Node) => boolean): boolean {
    if (!isElement(elem)) {
      throw new Error('Argument to isShown must be of type Element');
    }

    if (isElement(elem, 'BODY')) {
      return true;
    }

    if (isElement(elem, 'OPTION') || isElement(elem, 'OPTGROUP')) {
      var select = (elem as Element).closest('select');
      return !!select && isShownInternal(select, true, displayedFn);
    }

    var imageMap = maybeFindImageMap(elem);
    if (imageMap) {
      return !!imageMap.image && imageMap.rect.width > 0 && imageMap.rect.height > 0 &&
        isShownInternal(imageMap.image, ignoreOpacity, displayedFn);
    }

    if (isElement(elem, 'INPUT') && (elem as HTMLInputElement).type.toLowerCase() === 'hidden') {

View on GitHub (pinned to aa36b38e69)

Solutions

  1. Guard with isElement(elem) (nodeType === 1) before invoking isShownInternal.
  2. Re-acquire the element in the correct document context so it is a real Element in the realm where isShown runs.
  3. When selecting text nodes, resolve to the parent Element before the visibility call.
  4. Null-check findElement results before forwarding them to the atom.

Example fix

// before
function check(node) {
  return isShownInternal(node, false, displayedFn) // throws for Text nodes
}

// after
function check(node) {
  if (!isElement(node)) {
    if (node && node.parentElement) node = node.parentElement
    if (!isElement(node)) return false
  }
  return isShownInternal(node, false, displayedFn)
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (!isElement(elem)) {
  elem = elem && elem.parentElement
}
if (!isElement(elem)) return false

Type guard

function isElement(node, tag) {
  if (!node || node.nodeType !== 1) return false
  if (tag) return node.tagName === tag.toUpperCase()
  return true
}

Prevention

When it happens

Trigger: Calling the compiled isShown against a node that is not an Element (Text, Comment, Document, DocumentFragment, null). Using a sharedId/handle that resolves to a non-element node server-side. Passing a polyfilled or cross-realm object that fails the instanceof Element / isElement check despite looking element-like.

Common situations: Same family as the legacy atom: text-node XPath targets, stale cross-frame references, ShadowRoot passed instead of host. Additionally common when consumers of the TS atom pass a serialized element reference from a different execution context (e.g. an iframe's element into the top document's isShown).

Related errors


AI-assisted analysis of SeleniumHQ/selenium@aa36b38e69 (2026-08-14). Data as JSON: /api/errors/e06560b4bff4a39d. Report an issue: GitHub.