marmelab/react-admin · error · Error

useEditController requires an id prop or a route with an /:i

Error message

useEditController requires an id prop or a route with an /:id? parameter.

What it means

useEditController needs a record id to fetch and edit: it takes the id prop and falls back to the :id route parameter via useParams. If neither the id prop nor a route containing an /:id? segment is present, it cannot load a record and throws. Note the same hook can throw this even when the resource is correct (unlike error 3).

Source

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

        );
    }
    const { isPending: isPendingAuthenticated } = useAuthenticated({
        enabled: !disableAuthentication,
    });

    const { isPending: isPendingCanAccess } = useRequireAccess<RecordType>({
        action: 'edit',
        resource,
        enabled: !disableAuthentication && !isPendingAuthenticated,
    });

    const getRecordRepresentation = useGetRecordRepresentation(resource);
    const translate = useTranslate();
    const notify = useNotify();
    const redirect = useRedirect();
    const { id: routeId } = useParams<{ id?: string }>();
    if (!routeId && !propsId) {
        throw new Error(
            'useEditController requires an id prop or a route with an /:id? parameter.'
        );
    }
    const id = propsId ?? routeId;

    const { meta: queryMeta, ...otherQueryOptions } = queryOptions;
    const {
        meta: mutationMeta,
        onSuccess,
        onError,
        ...otherMutationOptions
    } = mutationOptions;

    if (
        (queryMeta || mutationMeta) &&
        JSON.stringify(queryMeta) !== JSON.stringify(mutationMeta) &&
        redirectTo === false
    ) {

View on GitHub (pinned to 051f511bb0)

Solutions

  1. Pass the id explicitly: `<Edit resource="posts" id={recordId}>`.
  2. Fix the route path to include the id parameter: `<Route path="posts/:id/edit">` or register via `<Resource name="posts" edit={PostEdit}>` so the default :id route is generated.
  3. Ensure react-router context exists (component rendered inside the Admin router) so useParams can read :id.
  4. If editing a freshly created record, redirect to the edit route with the new id instead of a bare edit path.

Example fix

// before
<Route path="posts/edit" element={<PostEdit />} />

// after
<Route path="posts/:id/edit" element={<PostEdit />} />
Defensive patterns

Strategy: validation

Validate before calling

// Confirm an id exists before rendering the edit view
const { id: routeId } = useParams<{ id?: string }>();
const id = propsId ?? routeId;
if (!id) throw new Error('Edit view requires an id prop or an /:id route parameter');

Type guard

function hasEditId(routeId?: string, propsId?: string | number): routeId is string {
  return Boolean(routeId ?? propsId);
}

Try / catch

// Pre-validate before rendering the controller:
const id = propsId ?? routeId;
if (!hasEditId(routeId, propsId)) {
  return <Navigate to="/" replace />; // or show an error page
}
const controller = useEditController({ resource, id });

Prevention

When it happens

Trigger: Rendering <Edit> on a route that lacks an :id parameter (e.g. path="posts/edit" instead of "posts/:id/edit"), or calling useEditController without an id prop outside a parameterized route.

Common situations: Custom <Route path="posts/edit"> definitions missing the :id segment; using useEditController in a modal that doesn't pass the record id; upgrading react-admin and moving Edit off the standard Resource route so useParams no longer supplies the id.

Related errors


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