facebook/relay · error

MatchContainer: Invalid 'match' value, expected an object th

Error message

MatchContainer: Invalid 'match' value, expected an object that has a '...SomeFragment' spread.

What it means

When `match` is an object, MatchContainer destructures Relay-injected metadata fields (__fragmentOwner, __fragmentPropName, __fragments, __id) added by fragment spreads. If any of those fields exist but has the wrong type — e.g. __id is present but not a string — the value was not produced by a real fragment spread, so the container throws. This validates that `match` came from Relay's fragment machinery rather than arbitrary user data.

Source

Thrown at packages/react-relay/relay-hooks/MatchContainer.js:135

  // spread matches, then the metadata fields below (__id, __fragments, etc.)
  // will be present. But they can be missing if all the fragment spreads use
  // @module and none of the types matched. The cast here is necessary because
  // fragment Flow types don't describe metadata fields, only the actual schema
  // fields the developer selected.
  const {
    __id,
    __fragments,
    __fragmentOwner,
    __fragmentPropName,
    __module_component,
  } = (match as $FlowFixMe) ?? {};
  if (
    (__fragmentOwner != null && typeof __fragmentOwner !== 'object') ||
    (__fragmentPropName != null && typeof __fragmentPropName !== 'string') ||
    (__fragments != null && typeof __fragments !== 'object') ||
    (__id != null && typeof __id !== 'string')
  ) {
    throw new Error(
      "MatchContainer: Invalid 'match' value, expected an object that has a " +
        "'...SomeFragment' spread.",
    );
  }

  const LoadedContainer =
    __module_component != null ? loader(__module_component) : null;

  const fragmentProps = useMemo(() => {
    // TODO: Perform this transformation in RelayReader so that unchanged
    // output of subscriptions already has a stable identity.
    if (__fragmentPropName != null && __id != null && __fragments != null) {
      const fragProps: {
        [string]: {
          __fragmentOwner: $FlowFixMe,
          __fragments: $FlowFixMe,
          __id: string,
        },

View on GitHub (pinned to 668b1b85e0)

Solutions

  1. Obtain `match` from reading a Relay fragment (useFragment/useClientFragment) on an @match field so all metadata fields are present and correctly typed
  2. Fix test mocks to include correctly typed __id (string), __fragments (object), __fragmentOwner (object), __fragmentPropName (string)
  3. Do not manually construct match objects; pass through the value Relay supplies

Example fix

// before
<MatchContainer match={{ __id: 123 }} />;

// after
const match = useFragment(graphql`fragment M on Resolver { ... }`, key);
<MatchContainer match={match} />;
Defensive patterns

Strategy: type-guard

Validate before calling

function validateMatchMetadata(match) {
  if (match == null) return match;
  const { __fragmentOwner: o, __fragmentPropName: p, __fragments: f, __id: id } = match;
  const bad =
    (o != null && typeof o !== 'object') ||
    (p != null && typeof p !== 'string') ||
    (f != null && typeof f !== 'object') ||
    (id != null && typeof id !== 'string');
  if (bad) throw new TypeError('match is not a valid fragment-spread value');
  return match;
}

Type guard

const hasValidSpreadMetadata = (m) =>
  m == null || (
    (m.__fragmentOwner == null || typeof m.__fragmentOwner === 'object') &&
    (m.__fragmentPropName == null || typeof m.__fragmentPropName === 'string') &&
    (m.__fragments == null || typeof m.__fragments === 'object') &&
    (m.__id == null || typeof m.__id === 'string')
  );

Try / catch

try {
  render(<MatchContainer match={value} />);
} catch (e) {
  if (String(e.message).includes("Invalid 'match' value")) {
    console.warn('Discarding invalid match value', value);
    render(<Spinner />);
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: Passing a plain object as `match` that lacks proper fragment-spread metadata, or an object whose __fragmentOwner/__fragments/__id/__fragmentPropName fields were hand-crafted with wrong types (e.g. __id as a number, __fragments as a string).

Common situations: Mocking resolver/match data for tests with hand-made objects missing correct metadata fields; serializing and deserializing match values (striping/dropping metadata); constructing match objects manually instead of reading them from a Relay fragment result.

Related errors


AI-assisted analysis of facebook/relay@668b1b85e0 (2026-09-02). Data as JSON: /api/errors/9738d5eb73fba096. Report an issue: GitHub.