emberjs/ember.js · error · Error

Attempted to cast to a browser node in a non-browser context

Error message

Attempted to cast to a browser node in a non-browser context

What it means

castToBrowser is a debug utility that casts a value to a browser DOM node, checking it against the global `document`. In non-browser environments (SSR, Node tests, workers) `document` is undefined, so the cast is impossible and this error is thrown.

Source

Thrown at packages/@glimmer/debug-util/lib/simple-cast.ts:83

): NodeForSugaryCheck<S>;
export function castToBrowser<K extends keyof HTMLElementTagNameMap>(
  element: SimpleElement | Element,
  check: K
): HTMLElementTagNameMap[K];
export function castToBrowser<S extends SugaryNodeCheck>(
  node: SimpleNode | BrowserNode | null | undefined,
  sugaryCheck?: S
): Document | NodeForSugaryCheck<S> | null {
  if (!LOCAL_DEBUG) {
    return node as Document | NodeForSugaryCheck<S> | null;
  }

  if (node === null || node === undefined) {
    return null;
  }

  if (typeof document === 'undefined') {
    throw new Error('Attempted to cast to a browser node in a non-browser context');
  }

  if (isDocument(node)) {
    return node as Document;
  }

  if (node.ownerDocument !== document) {
    throw new Error(
      'Attempted to cast to a browser node with a node that was not created from this document'
    );
  }

  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- @fixme
  return checkBrowserNode(node, sugaryCheck!);
}

function checkError(from: string, check: SugaryNodeCheck): Error {
  return new Error(`cannot cast a ${from} into ${String(check)}`);

View on GitHub (pinned to 26f97246a8)

Solutions

  1. Only call castToBrowser in browser contexts; guard with `typeof document !== 'undefined'`
  2. For SSR, use environment-agnostic code paths that skip DOM casting
  3. Configure tests to run in a DOM environment (jsdom/happy-dom)
  4. Polyfill a document if the environment is supposed to be browser-like

Example fix

// before
let node = castToBrowser(maybeNode, 'Element');
// after
if (typeof document !== 'undefined') {
  let node = castToBrowser(maybeNode, 'Element');
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof document === 'undefined') {
  throw new Error('castToBrowser requires a browser environment (document is undefined)');
}

Type guard

function inBrowser(): boolean {
  return typeof document !== 'undefined' && document.nodeType === 9;
}

Try / catch

try {
  node = castToBrowser(value, 'Element');
} catch (e) {
  if (String(e.message).includes('non-browser context')) {
    node = null; // SSR path
  } else { throw e; }
}

Prevention

When it happens

Trigger: Calling castToBrowser (directly or via input/option/marker helpers) when `typeof document === 'undefined'` — server-side rendering, Node-only unit tests, web workers.

Common situations: Running Glimmer SSR where code paths touch DOM-casting helpers; running tests in Node without jsdom; accidentally importing DOM utilities into server bundles.

Related errors


AI-assisted analysis of emberjs/ember.js@26f97246a8 (2026-09-01). Data as JSON: /api/errors/f983be06e7ce7869. Report an issue: GitHub.