facebook/relay · error

The __id field must be present on each item passed to the se

Error message

The __id field must be present on each item passed to the setter. This indicates a bug in Relay.

What it means

Each item passed to a plural linked field setter must be a record proxy exposing a `__id` (data ID). This error fires when an item lacks `__id`, and Relay states it indicates a bug in Relay itself, since proxies returned by the library always carry it.

Source

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

  updatableProxyRootRecord: RecordProxy,
  recordSourceProxy: RecordSourceProxy,
) {
  return function set(newValue: ReadonlyArray<{__id: string, ...}>) {
    const newVariables = getArgumentValues(selection.args ?? [], variables);
    if (newValue == null) {
      throw new Error(
        'Do not assign null to plural linked fields; assign an empty array instead.',
      );
    } else {
      const recordProxies = newValue.map((item): ?RecordProxy => {
        if (item == null) {
          throw new Error(
            'When assigning an array of items, none of the items should be null or undefined.',
          );
        }
        const {__id} = item;
        if (__id == null) {
          throw new Error(
            'The __id field must be present on each item passed to the setter. This indicates a bug in Relay.',
          );
        }
        const newValueRecord = recordSourceProxy.get(__id);
        if (newValueRecord == null) {
          throw new Error(
            `Did not find item with data id ${__id} in the store.`,
          );
        }
        return newValueRecord;
      });
      updatableProxyRootRecord.setLinkedRecords(
        recordProxies,
        selection.name,
        newVariables,
      );
    }
  };

View on GitHub (pinned to 668b1b85e0)

Solutions

  1. Only pass records obtained from the updatable proxy (e.g. `updatable.viewer.friends.get()[0]`) or existing linked records into the setter
  2. Read the target records from `store.get(id)`/`recordSourceProxy.get(id)` rather than using raw response payloads
  3. If items come from another source, copy their fields into store records first, then assign those records
  4. If you are passing valid RecordProxies and still see this, file a bug with Relay — the message signals an internal invariant

Example fix

// before
updatable.viewer.friends.set(response.updateUser.friends); // raw payload objects
// after
const updated = updatable.viewer.friends.get();
updatable.viewer.friends.set(updated); // record proxies from the store
Defensive patterns

Strategy: type-guard

Validate before calling

function isRecordProxyLike(item) {
  return item != null && typeof item === 'object' && typeof item.__id === 'string' && item.__id.length > 0;
}
items.forEach(item => { if (!isRecordProxyLike(item)) throw new TypeError('Setter requires store record proxies with __id'); });

Type guard

function isRecordProxy(item: unknown): item is {__id: string} {
  return typeof item === 'object' && item !== null && typeof (item as any).__id === 'string';
}

Try / catch

try {
  field.set(items);
} catch (e) {
  if (e.message.includes('__id field must be present')) throw new Error('Pass record proxies from the updatable proxy/store, not raw payload objects', {cause: e});
  throw e;
}

Prevention

When it happens

Trigger: Passing raw plain objects (fetched manually or constructed inline) instead of RecordProxies from the updatable proxy into `pluralField.set(...)` — such objects have no `__id` property.

Common situations: Assigning raw mutation response objects instead of records read from the same updatable proxy; mixing records from a different RecordSource; a Relay internals regression.

Related errors


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