marmelab/react-admin · error · Error

useUpdateMany mutation requires an array of ids

Error message

useUpdateMany mutation requires an array of ids

What it means

react-admin's useUpdateMany hook validates its mutate arguments before calling the dataProvider. If params.ids is null or undefined it throws immediately, because updateMany is meaningless without the list of record ids to update.

Source

Thrown at packages/ra-core/src/dataProvider/useUpdateMany.ts:107

        mutationMode = 'pessimistic',
        getMutateWithMiddlewares,
        mutationFn: customMutationFn,
        ...mutationOptions
    } = options;

    const dataProviderUpdateMany = useEvent(
        (resource: string, params: UpdateManyParams<RecordType>) =>
            dataProvider.updateMany<RecordType>(resource, params)
    );
    const customMutationFnWithDataProviderResult = async (
        resource: string | undefined,
        params: Omit<UseUpdateManyMutateParams<RecordType>, 'resource'>
    ) => {
        if (resource == null) {
            throw new Error('useUpdateMany mutation requires a resource');
        }
        if (params.ids == null) {
            throw new Error('useUpdateMany mutation requires an array of ids');
        }
        if (!params.data) {
            throw new Error(
                'useUpdateMany mutation requires a non-empty data object'
            );
        }
        if (customMutationFn == null) {
            return dataProviderUpdateMany(
                resource,
                params as UpdateManyParams<RecordType>
            );
        }

        return {
            data: await customMutationFn({ resource, ...params }),
        };
    };

View on GitHub (pinned to 051f511bb0)

Solutions

  1. Guard the call: only invoke mutate when Array.isArray(ids) && ids.length > 0.
  2. Initialize selection state as [] rather than null/undefined.
  3. Pass the correct key — useUpdateMany expects { ids, data }, not { id, data } (that is useUpdate).
  4. Check the ids variable is not shadowed or assigned after the mutate call.

Example fix

// before
mutate({ ids: selectedIds, data: { status: 'archived' } }); // selectedIds may be null
// after
if (selectedIds && selectedIds.length > 0) {
    mutate({ ids: selectedIds, data: { status: 'archived' } });
}
Defensive patterns

Strategy: validation

Validate before calling

const canUpdate = Array.isArray(selectedIds) && selectedIds.length > 0 && data != null;
if (canUpdate) mutate({ ids: selectedIds, data });

Type guard

const hasIds = (p: { ids?: unknown }): p is { ids: unknown[] } =>
    Array.isArray(p.ids);

Try / catch

try {
    mutate({ ids, data });
} catch (e) {
    if (e instanceof Error && e.message.includes('requires an array of ids')) {
        notify('Select at least one record first', { type: 'warning' });
    }
}

Prevention

When it happens

Trigger: Calling mutate({ ids: undefined, data }) — e.g. ids derived from a selection state that was never populated, or a variable that is still null when the mutation fires.

Common situations: Bulk-update toolbars on a Datagrid where the selected-ids state starts empty and the mutation runs before the user selects rows; passing the wrong prop (id instead of ids); an async source for ids that resolves after the mutate call.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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