{"record":{"id":"ee8648e1f572ad6b","repo":"marmelab/react-admin","slug":"useupdatemany-mutation-requires-an-array-of-ids","errorCode":null,"errorMessage":"useUpdateMany mutation requires an array of ids","messagePattern":"useUpdateMany mutation requires an array of ids","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/ra-core/src/dataProvider/useUpdateMany.ts","lineNumber":107,"sourceCode":"        mutationMode = 'pessimistic',\n        getMutateWithMiddlewares,\n        mutationFn: customMutationFn,\n        ...mutationOptions\n    } = options;\n\n    const dataProviderUpdateMany = useEvent(\n        (resource: string, params: UpdateManyParams<RecordType>) =>\n            dataProvider.updateMany<RecordType>(resource, params)\n    );\n    const customMutationFnWithDataProviderResult = async (\n        resource: string | undefined,\n        params: Omit<UseUpdateManyMutateParams<RecordType>, 'resource'>\n    ) => {\n        if (resource == null) {\n            throw new Error('useUpdateMany mutation requires a resource');\n        }\n        if (params.ids == null) {\n            throw new Error('useUpdateMany mutation requires an array of ids');\n        }\n        if (!params.data) {\n            throw new Error(\n                'useUpdateMany mutation requires a non-empty data object'\n            );\n        }\n        if (customMutationFn == null) {\n            return dataProviderUpdateMany(\n                resource,\n                params as UpdateManyParams<RecordType>\n            );\n        }\n\n        return {\n            data: await customMutationFn({ resource, ...params }),\n        };\n    };\n","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/marmelab/react-admin/blob/051f511bb0afb5ea565c2d3728bf4dab0a6fa5e0/packages/ra-core/src/dataProvider/useUpdateMany.ts#L89-L125","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Guard the call: only invoke mutate when Array.isArray(ids) && ids.length > 0.","Initialize selection state as [] rather than null/undefined.","Pass the correct key — useUpdateMany expects { ids, data }, not { id, data } (that is useUpdate).","Check the ids variable is not shadowed or assigned after the mutate call."],"exampleFix":"// before\nmutate({ ids: selectedIds, data: { status: 'archived' } }); // selectedIds may be null\n// after\nif (selectedIds && selectedIds.length > 0) {\n    mutate({ ids: selectedIds, data: { status: 'archived' } });\n}","handlingStrategy":"validation","validationCode":"const canUpdate = Array.isArray(selectedIds) && selectedIds.length > 0 && data != null;\nif (canUpdate) mutate({ ids: selectedIds, data });","typeGuard":"const hasIds = (p: { ids?: unknown }): p is { ids: unknown[] } =>\n    Array.isArray(p.ids);","tryCatchPattern":"try {\n    mutate({ ids, data });\n} catch (e) {\n    if (e instanceof Error && e.message.includes('requires an array of ids')) {\n        notify('Select at least one record first', { type: 'warning' });\n    }\n}","preventionTips":["Initialize ids state as [], never null/undefined.","Gate mutate behind ids.length > 0.","Type the payload with UpdateManyParams so ids is required at compile time.","Unit test the mutate call with an empty selection."],"tags":["react-admin","mutation","validation","developer-error"],"backgroundTag":"missing-required-argument","analyzedSha":"051f511bb0afb5ea565c2d3728bf4dab0a6fa5e0","analyzedAt":"2026-08-30T02:28:14.926Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}