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
- Obtain `match` from reading a Relay fragment (useFragment/useClientFragment) on an @match field so all metadata fields are present and correctly typed
- Fix test mocks to include correctly typed __id (string), __fragments (object), __fragmentOwner (object), __fragmentPropName (string)
- 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
- Never hand-construct match objects; always pass Relay fragment results through
- Fix test mocks to include correctly typed __id/__fragments/__fragmentOwner/__fragmentPropName
- Avoid serializing match values across boundaries (e.g. server->client) where metadata can be dropped
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
- MatchContainer: Expected `match` value to be an object or nu
- useRefetchableFragmentNode: Unexpected action type
- useRefetchableFragmentNode: Unexpected action type
AI-assisted analysis of facebook/relay@668b1b85e0 (2026-09-02).
Data as JSON: /api/errors/9738d5eb73fba096.
Report an issue: GitHub.