marmelab/react-admin · error · Error
useEditController: Fetched record's id attribute (${record.i
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.
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)
Solutions
- Fix the dataProvider's getOne so it returns exactly the record whose id was requested (verify the backend endpoint honors the :id parameter).
- Ensure the backend lookup key matches the id react-admin passes (check the route param / id parsing, e.g. parseInt on numeric ids).
- Check test fixtures / mocked getOne responses return a record with the same id that the component requests.
- 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
- Always implement getOne as `${apiUrl}/${resource}/${params.id}` so the id is honored server-side.
- Test dataProvider.getOne with two different ids and assert the returned record ids differ accordingly.
- Normalize id types (number vs string) consistently between routes, backend, and fixtures.
- Never reuse mocked getOne responses across test ids.
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
- useShowController: Fetched record's id attribute (${record.i
- create is not implemented
- delete not implemented
- deleteMany is not implemented
- getList is not implemented
AI-assisted analysis of marmelab/react-admin@051f511bb0 (2026-08-30).
Data as JSON: /api/errors/075e40d917f5d3d4.
Report an issue: GitHub.