marmelab/react-admin · error · Error

useEditController: Fetched record's id attribute

Error message

useEditController: Fetched record's id attribute (${record.id}) must match the requested 'id' (${id})

What it means

useEditController (used internally by <Edit> / useEditController) fetches a single record by the id taken from the route/props. After the data provider returns, it checks that the fetched record's own `id` attribute equals the requested id (loose equality). If the data provider returned a record with a different id, react-admin throws because rendering an edit form for the wrong record would silently corrupt data.

Solutions

  1. Fix the dataProvider's getOne so it returns exactly the record whose id was requested (verify the backend endpoint honors the :id parameter).
  2. Ensure the backend lookup key matches the id react-admin passes (check the route param / id parsing, e.g. parseInt on numeric ids).
  3. Check test fixtures / mocked getOne responses return a record with the same id that the component requests.
  4. Confirm you are not reusing an <Edit> or useEditController instance across resources without setting the correct `resource` prop.

Example fix

// before: dataProvider ignores the requested id
getOne: (resource, params) => fetch(`${apiUrl}/${resource}`).then(...)
// after: request the specific record by id
getOne: (resource, params) =>
  fetch(`${apiUrl}/${resource}/${params.id}`).then(...)
Defensive patterns

Strategy: validation

Validate before calling

// validate what the dataProvider will return for this id before rendering Edit
const record = await dataProvider.getOne(resource, { id }).then(r => r.data);
if (record?.id != null && String(record.id) !== String(id)) {
  throw new Error(`dataProvider returned record id ${record.id} for requested id ${id}`);
}

Type guard

const isRecordForId = (record, id) =>
  record != null && record.id != null && String(record.id) === String(id);

Try / catch

try {
  render(<Edit id={id} resource={resource} />);
} catch (e) {
  if (String(e.message).includes("must match the requested 'id'")) {
    // report dataProvider bug / reload record
  } else throw e;
}

Prevention

When it happens

Trigger: Calling useEditController (or <Edit>) where the query for `id` returns a record whose `record.id` differs, e.g. a misconfigured dataProvider that ignores the requested id (getOne returning a cached or first record), a backend that looks up by another key, or string-vs-number routing ids resolved against the wrong resource.

Common situations: Custom dataProviders that cache aggressively and return the most recent record regardless of id; backends whose GET /posts/:id endpoint ignores the :id param and returns a default document; copying an <Edit> component between resources without changing the resource prop so the provider resolves a record from another table; tests mocking getOne with a hardcoded record id.

Related errors


AI-assisted analysis of marmelab/react-admin@051f511bb0 (2026-08-30). Data as JSON: /api/errors/075e40d917f5d3d4. Report an issue: GitHub.

Appendix: source

Thrown at packages/ra-core/src/controller/edit/useEditController.ts:147

            enabled:
                (!isPendingAuthenticated && !isPendingCanAccess) ||
                disableAuthentication,
            onError: () => {
                notify('ra.notification.item_doesnt_exist', {
                    type: 'error',
                });
                redirect(redirectOnError, resource, id);
            },
            refetchOnReconnect: false,
            refetchOnWindowFocus: false,
            retry: false,
            ...otherQueryOptions,
        }
    );

    // eslint-disable-next-line eqeqeq
    if (record && record.id && record.id != id) {
        throw new Error(
            `useEditController: Fetched record's id attribute (${record.id}) must match the requested 'id' (${id})`
        );
    }

    const getResourceLabel = useGetResourceLabel();
    const recordRepresentation = getRecordRepresentation(record);
    const defaultTitle = translate(`resources.${resource}.page.edit`, {
        id,
        record,
        recordRepresentation:
            typeof recordRepresentation === 'string'
                ? recordRepresentation
                : '',
        _: translate('ra.page.edit', {
            name: getResourceLabel(resource, 1),
            id,
            record,
            recordRepresentation:

View on GitHub (pinned to 051f511bb0)