{"record":{"id":"c090665332bc2491","repo":"marmelab/react-admin","slug":"useupdatemany-mutation-requires-a-resource","errorCode":null,"errorMessage":"useUpdateMany mutation requires a resource","messagePattern":"useUpdateMany mutation requires a resource","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/ra-core/src/dataProvider/useUpdateMany.ts","lineNumber":104,"sourceCode":"    const dataProvider = useDataProvider();\n    const queryClient = useQueryClient();\n    const {\n        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 }),","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/marmelab/react-admin/blob/051f511bb0afb5ea565c2d3728bf4dab0a6fa5e0/packages/ra-core/src/dataProvider/useUpdateMany.ts#L86-L122","documentation":"useUpdateMany wraps dataProvider.updateMany for bulk edits; its mutate takes the resource as the first argument. A null/undefined resource leaves the target collection unknown, so the hook throws before invoking the data provider.","triggerScenarios":"Calling mutate(undefined, { ids, data }); resource from an undefined route param; bulk-edit dialog rendered outside a Resource context so useResourceContext returns undefined.","commonSituations":"Bulk-edit modals reused across pages without passing the resource; refactors that removed a resource prop; dynamic resources resolved from URL that are absent on the current route.","solutions":["Pass the resource string: mutate('posts', { ids, data }).","Use useResourceContext() and gate rendering on it being defined.","Forward the resource prop explicitly into bulk-edit dialogs."],"exampleFix":"// before\nupdateMany(resource, { ids, data }); // resource undefined\n// after\nconst resource = useResourceContext();\nif (!resource) return;\nupdateMany(resource, { ids, data });","handlingStrategy":"validation","validationCode":"if (typeof resource !== 'string' || resource.length === 0) {\n  throw new TypeError('useUpdateMany: resource must be a non-empty string');\n}","typeGuard":"const hasResource = (r: unknown): r is string => typeof r === 'string' && r.length > 0;","tryCatchPattern":"try {\n  await mutate(resource!, { ids, data });\n} catch (e) {\n  if (e instanceof Error && e.message.includes('requires a resource')) {\n    notify('Bulk update failed: unknown resource', { type: 'warning' });\n  } else throw e;\n}","preventionTips":["Pass resource explicitly into bulk-edit dialogs.","Resolve resource via useResourceContext() and gate rendering.","Add runtime checks in shared bulk-action components."],"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"}