{"record":{"id":"1a3cdddebf97ca4f","repo":"marmelab/react-admin","slug":"usedeletemany-mutation-requires-an-array-of-ids","errorCode":null,"errorMessage":"useDeleteMany mutation requires an array of ids","messagePattern":"useDeleteMany mutation requires an array of ids","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/ra-core/src/dataProvider/useDeleteMany.ts","lineNumber":107,"sourceCode":"    options: UseDeleteManyOptions<RecordType, MutationError> = {}\n): UseDeleteManyResult<RecordType, MutationError> => {\n    const dataProvider = useDataProvider();\n    const queryClient = useQueryClient();\n    const {\n        mutationMode = 'pessimistic',\n        mutationFn: customMutationFn,\n        onSettled,\n        ...mutationOptions\n    } = options;\n    const customMutationFnWithDataProviderResult = async (\n        resource: string | undefined,\n        params: Omit<UseDeleteManyMutateParams<RecordType>, 'resource'>\n    ) => {\n        if (resource == null) {\n            throw new Error('useDeleteMany mutation requires a resource');\n        }\n        if (params.ids == null) {\n            throw new Error('useDeleteMany mutation requires an array of ids');\n        }\n        if (customMutationFn == null) {\n            return dataProvider.deleteMany<RecordType>(\n                resource,\n                params as DeleteManyParams<RecordType>\n            );\n        }\n\n        return {\n            data: await customMutationFn({ resource, ...params }),\n        };\n    };\n\n    const [mutate, mutationResult] = useMutationWithMutationMode<\n        MutationError,\n        DeleteManyResult<RecordType>,\n        UseDeleteManyMutateParams<RecordType>\n    >(","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/marmelab/react-admin/blob/051f511bb0afb5ea565c2d3728bf4dab0a6fa5e0/packages/ra-core/src/dataProvider/useDeleteMany.ts#L89-L125","documentation":"useDeleteMany's mutate requires an ids array identifying which records to delete. When params.ids is null or undefined, the library cannot build a deleteMany call and throws. This guards against malformed mutation arguments reaching the data provider.","triggerScenarios":"Calling mutate('posts', {}) or mutate('posts', { ids: undefined }); passing ids from a selection state that was never initialized (e.g. selectedIds from an empty/unmounted data table); TypeScript disabled so the Omit<UseDeleteManyMutateParams> shape is not enforced.","commonSituations":"Bulk-delete buttons clicked before row selection state loads; storing selectedIds in a store that resets to undefined; hand-rolled calls that pass ids as a non-array like a single id.","solutions":["Always pass an array: mutate('posts', { ids: selectedIds }).","Default selection state to [] instead of undefined.","Disable the delete action until ids is a non-empty array."],"exampleFix":"// before\ndeleteMany('posts', { ids: selectedIds }); // selectedIds?: Identifier[]\n// after\ndeleteMany('posts', { ids: selectedIds ?? [] });","handlingStrategy":"validation","validationCode":"if (!Array.isArray(ids) || ids.length === 0) {\n  throw new TypeError('useDeleteMany: ids must be a non-empty array');\n}","typeGuard":"const hasIds = (v: unknown): v is Array<string | number> => Array.isArray(v) && v.length > 0;","tryCatchPattern":"try {\n  await mutate(resource, { ids });\n} catch (e) {\n  if (e instanceof Error && e.message.includes('array of ids')) {\n    notify('Select at least one record first', { type: 'warning' });\n  } else throw e;\n}","preventionTips":["Initialize selection state to [] not undefined.","Disable bulk-delete buttons until selectedIds.length > 0.","Type mutate params explicitly so TS catches missing ids."],"tags":["react-admin","mutation","missing-argument","validation"],"backgroundTag":"missing-required-argument","analyzedSha":"051f511bb0afb5ea565c2d3728bf4dab0a6fa5e0","analyzedAt":"2026-08-30T02:28:14.926Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}