{"record":{"id":"9988ae316d0e04c8","repo":"marmelab/react-admin","slug":"usedelete-mutation-requires-a-non-empty-id","errorCode":null,"errorMessage":"useDelete mutation requires a non-empty id","messagePattern":"useDelete mutation requires a non-empty id","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/ra-core/src/dataProvider/useDelete.ts","lineNumber":107,"sourceCode":"    options: UseDeleteOptions<RecordType, MutationError> = {}\n): UseDeleteResult<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<UseDeleteMutateParams<RecordType>, 'resource'>\n    ) => {\n        if (resource == null) {\n            throw new Error('useDelete mutation requires a resource');\n        }\n        if (params.id == null) {\n            throw new Error('useDelete mutation requires a non-empty id');\n        }\n        if (customMutationFn == null) {\n            return dataProvider.delete<RecordType>(\n                resource,\n                params as DeleteParams<RecordType>\n            );\n        }\n\n        return {\n            data: await customMutationFn({ resource, ...params }),\n        };\n    };\n\n    const [mutate, mutationResult] = useMutationWithMutationMode<\n        MutationError,\n        DeleteResult<RecordType>,\n        UseDeleteMutateParams<RecordType>\n    >(","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/marmelab/react-admin/blob/051f511bb0afb5ea565c2d3728bf4dab0a6fa5e0/packages/ra-core/src/dataProvider/useDelete.ts#L89-L125","documentation":"useDelete validates that params.id is non-null before deleting, since a delete call without a record id is invalid. The check occurs before the data provider is contacted.","triggerScenarios":"Calling mutate(resource, {}) without id, or mutating while the record is still loading so record.id is undefined.","commonSituations":"Delete buttons rendered before useGetOne resolves; list selection rows where the selected id was never stored in state.","solutions":["Always pass an id: mutate('posts', { id: record.id })","Disable/guard the delete button until the record is loaded","Validate id != null before invoking the mutation"],"exampleFix":"// before\nmutate('posts', { id: record?.id });\n// after\nif (record?.id != null) mutate('posts', { id: record.id });","handlingStrategy":"validation","validationCode":"if (id == null) {\n  throw new Error('Cannot delete: record id is missing');\n}\nmutate('posts', { id });","typeGuard":"const hasId = (p: { id?: Identifier | null }): p is { id: Identifier } =>\n  p.id !== undefined && p.id !== null;","tryCatchPattern":"try {\n  await mutate('posts', { id });\n} catch (e) {\n  if (/requires a non-empty id/.test(e.message)) {\n    notify('No record selected to delete', { type: 'warning' });\n    return;\n  }\n  throw e;\n}","preventionTips":["Render delete buttons only after the record query has loaded (isLoading)","Guard selection-based deletes on non-empty selection arrays","Use non-null assertions sparingly; prefer runtime checks on record.id"],"tags":["react-admin","usedelete","mutation","validation"],"backgroundTag":"missing-required-argument","analyzedSha":"051f511bb0afb5ea565c2d3728bf4dab0a6fa5e0","analyzedAt":"2026-08-30T02:28:14.926Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}