facebook/relay · error

Encountered an unexpected ReaderSelection variant in RelayRe

Error message

Encountered an unexpected ReaderSelection variant in RelayRecordSourceProxy. This indicates a bug in Relay.

What it means

createUpdatableProxy walks reader selections to build updatable proxies for optimistic updates. ReaderSelection kinds like RequiredField, CatchField, Stream, RelayResolver, and RelayLiveResolver are not supported inside updatable mutation proxies; hitting one throws this 'bug in Relay' invariant via the explicit case branch.

Source

Thrown at packages/relay-runtime/mutations/createUpdatableProxy.js:190

        break;
      case 'FragmentSpread':
        // Explicitly ignore
        break;
      case 'Condition':
      case 'ActorChange':
      case 'InlineDataFragmentSpread':
      case 'AliasedInlineFragmentSpread':
      case 'ClientEdgeToClientObject':
      case 'ClientEdgeToServerObject':
      case 'Defer':
      case 'ModuleImport':
      case 'RequiredField':
      case 'CatchField':
      case 'Stream':
      case 'RelayResolver':
      case 'RelayLiveResolver':
        // These types of reader nodes are not currently handled.
        throw new Error(
          'Encountered an unexpected ReaderSelection variant in RelayRecordSourceProxy. This indicates a bug in Relay.',
        );
      default:
        selection.kind as empty;
        throw new Error(
          'Encountered an unexpected ReaderSelection variant in RelayRecordSourceProxy. This indicates a bug in Relay.',
        );
    }
  }
}

function createSetterForPluralLinkedField(
  selection: ReaderLinkedField,
  variables: Variables,
  updatableProxyRootRecord: RecordProxy,
  recordSourceProxy: RecordSourceProxy,
) {
  return function set(newValue: ReadonlyArray<{__id: string, ...}>) {

View on GitHub (pinned to 668b1b85e0)

Solutions

  1. Remove or restructure @required/@catch/@stream/Resolver fields from the selection set used by the updatable mutation
  2. Split the mutation so unhandled reader kinds are not part of the updatable region (select plain scalar/object fields only)
  3. Upgrade Relay to a newer version that may support these reader variants in updatable proxies
  4. If nothing above applies, reproduce and file a Relay bug — this path is an internal invariant

Example fix

// before
fragment F on User { name @catch { message } }
// after (updatable fragment)
fragment F on User { name }
Defensive patterns

Strategy: try-catch

Validate before calling

// Keep updatable fragments limited to plain fields; detect unsupported directives before compiling mutations
// e.g. lint rule: fail if @catch/@required/@stream/Resolver fields appear in updatable fragments

Try / catch

try {
  commitMutation(env, {mutation, variables, optimisticUpdater: store => {...}});
} catch (e) {
  if (e.message.includes('unexpected ReaderSelection variant')) {
    // retry without the optimistic updater / report the artifact
  }
}

Prevention

When it happens

Trigger: Performing an optimistic/updatable mutation whose @required/@catch-wrapped fields, @stream directives, or Relay Resolver / Live Resolver fields fall inside the mutation's updatable selection set.

Common situations: Adding @catch or @required directives or a client-side Resolver field to a type that participates in an updatable mutation; migrating a schema to Relay Resolvers while keeping legacy optimistic updates over those fields.

Related errors


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