facebook/react · error

365

365

Error message

Invalid selector type specified.

What it means

matchSelector switches on selector.$$typeof and recognizes only the selector types the test-selector module defines (component, role, test name/ID, text, and the :has pseudo-class selector). Anything else falls into the default branch and throws (error code 365). In practice this means a hand-built selector object, a selector that lost its Symbol identity, or a selector created by a different React copy whose $$typeof symbols do not match the copy performing the match.

Source

Thrown at packages/react-reconciler/src/ReactTestSelectors.js:208

      break;
    case TEST_NAME_TYPE:
      if (
        tag === HostComponent ||
        tag === HostHoistable ||
        tag === HostSingleton
      ) {
        const dataTestID = fiber.memoizedProps['data-testname'];
        if (
          typeof dataTestID === 'string' &&
          dataTestID.toLowerCase() ===
            (selector as any as TestNameSelector).value.toLowerCase()
        ) {
          return true;
        }
      }
      break;
    default:
      throw new Error('Invalid selector type specified.');
  }

  return false;
}

function selectorToString(selector: Selector): string | null {
  switch (selector.$$typeof) {
    case COMPONENT_TYPE:
      const displayName = getComponentNameFromType(selector.value) || 'Unknown';
      return `<${displayName}>`;
    case HAS_PSEUDO_CLASS_TYPE:
      return `:has(${selectorToString(selector) || ''})`;
    case ROLE_TYPE:
      return `[role="${(selector as any as RoleSelector).value}"]`;
    case TEXT_TYPE:
      return `"${(selector as any as TextSelector).value}"`;
    case TEST_NAME_TYPE:
      return `[data-testname="${(selector as any as TestNameSelector).value}"]`;

View on GitHub (pinned to eafeac097b)

Solutions

  1. Build selectors only with the provided factories: createTestNameSelector, createComponentSelector, createRoleSelector, createTextSelector, createHasPseudoClassSelector
  2. Dedupe react so the creator and the matcher share one copy and its symbols (npm ls react)
  3. Never hand-write, cache across builds, or JSON-serialize selector objects — construct them at query time

Example fix

// before
findAllNodes(root, [{$$typeof: Symbol.for('react.test_name'), value: 'feed'}]); // hand-built

// after
import {createTestNameSelector} from 'react-reconciler'; // same React copy as the matcher
findAllNodes(root, [createTestNameSelector('feed')]);
Defensive patterns

Strategy: type-guard

Validate before calling

// always construct selectors through the factories of the same React copy
import {createTestNameSelector} from '.../test-selectors';
const selectors = [createTestNameSelector('feed')];
findAllNodes(root, selectors);

Type guard

const KNOWN_SELECTOR_TYPES = new Set([
  COMPONENT_TYPE,
  ROLE_TYPE,
  TEST_NAME_TYPE,
  TEXT_TYPE,
  HAS_PSEUDO_CLASS_TYPE,
]); // import the TYPE constants from the same React copy that will match
const isValidSelector = (s) =>
  s != null && typeof s === 'object' && KNOWN_SELECTOR_TYPES.has(s.$$typeof);

Prevention

When it happens

Trigger: Passing an object literal without a recognized $$typeof into findAllNodes/selector matching; passing selectors built by a second react/react-reconciler instance whose TEST_NAME_TYPE/ROLE_TYPE symbols differ from the one matching; selectors that survived JSON round-tripping (Symbols are lost).

Common situations: Duplicate react packages in a bundle where one builds the selector and another matches it; serialized test fixtures of selectors; hand-rolled selector objects copied from an older React version's shape.

Related errors


AI-assisted analysis of facebook/react@eafeac097b (2026-08-21). Data as JSON: /api/errors/af60c40ddf2aa714. Report an issue: GitHub.