facebook/relay · error

The __id field must be present on the argument. This indicat

Error message

The __id field must be present on the argument. This indicates a bug in Relay.

What it means

When assigning a singular linked field through an updatable proxy, the new value must carry a `__id` (data ID) so Relay can link the corresponding store record. A value without `__id` is not a valid record reference; Relay declares this an internal invariant violation.

Source

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

      );
    }
  };
}

function createSetterForSingularLinkedField(
  selection: ReaderLinkedField,
  variables: Variables,
  updatableProxyRootRecord: RecordProxy,
  recordSourceProxy: RecordSourceProxy,
) {
  return function set(newValue: ?{__id: string, ...}) {
    const newVariables = getArgumentValues(selection.args ?? [], variables);
    if (newValue == null) {
      updatableProxyRootRecord.setValue(newValue, selection.name, newVariables);
    } else {
      const {__id} = newValue;
      if (__id == null) {
        throw new Error(
          'The __id field must be present on the argument. 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.`);
      }
      updatableProxyRootRecord.setLinkedRecord(
        newValueRecord,
        selection.name,
        newVariables,
      );
    }
  };
}

function createGetterForPluralLinkedField(
  selection: ReaderLinkedField,

View on GitHub (pinned to 668b1b85e0)

Solutions

  1. Assign records obtained via `updatable.<field>.get()` or `store.get(id)` — never raw payload objects
  2. If you have a data ID, do `store.get(id)` first and set the returned record
  3. Copy needed fields from the raw object into a store record, then assign that record
  4. If a genuine RecordProxy lacks `__id`, report it as a Relay bug

Example fix

// before
updatable.viewer.bestFriend.set(response.updateUser.bestFriend); // raw object
// after
const friend = store.get(response.updateUser.bestFriend.id);
updatable.viewer.bestFriend.set(friend);
Defensive patterns

Strategy: type-guard

Validate before calling

function isRecordProxyLike(v) {
  return v != null && typeof v === 'object' && typeof v.__id === 'string' && v.__id.length > 0;
}
if (next != null && !isRecordProxyLike(next)) throw new TypeError('Singular setter requires a record proxy with __id');

Type guard

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

Try / catch

try {
  field.set(next);
} catch (e) {
  if (e.message.includes('__id field must be present')) throw new Error('Assign store records, not raw payload objects', {cause: e});
  throw e;
}

Prevention

When it happens

Trigger: Calling `singularField.set(value)` with a raw object (e.g. a mutation response payload or inline object literal) that has no `__id`, instead of a record proxy from the store/updatable proxy.

Common situations: Assigning raw GraphQL response data directly in an updater; constructing `set({...})` with object literals; TypeScript types not narrowing away plain objects.

Related errors


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