{"record":{"id":"f1758b3970d0310a","repo":"marmelab/react-admin","slug":"usemutationwithmutationmode-mutation-requires-a-mu","errorCode":null,"errorMessage":"useMutationWithMutationMode mutation requires a mutationFn","messagePattern":"useMutationWithMutationMode mutation requires a mutationFn","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/ra-core/src/dataProvider/useMutationWithMutationMode.ts","lineNumber":37,"sourceCode":">(\n    params: TVariables = {} as TVariables,\n    options: UseMutationWithMutationModeOptions<ErrorType, TData, TVariables>\n): UseMutationWithMutationModeResult<boolean, ErrorType, TData, TVariables> => {\n    const queryClient = useQueryClient();\n    const addUndoableMutation = useAddUndoableMutation();\n    const {\n        mutationKey,\n        mutationMode = 'pessimistic',\n        mutationFn,\n        getMutateWithMiddlewares,\n        updateCache,\n        getQueryKeys,\n        onUndo,\n        ...mutationOptions\n    } = options;\n\n    if (mutationFn == null) {\n        throw new Error(\n            'useMutationWithMutationMode mutation requires a mutationFn'\n        );\n    }\n\n    const mutationFnEvent = useEvent(mutationFn);\n    const updateCacheEvent = useEvent(updateCache);\n    const getQueryKeysEvent = useEvent(getQueryKeys);\n    const getSnapshotEvent = useEvent(\n        /**\n         * Snapshot the previous values via queryClient.getQueriesData()\n         *\n         * The snapshotData ref will contain an array of tuples [query key, associated data]\n         *\n         * @example\n         * [\n         *   [['posts', 'getList'], { data: [{ id: 1, title: 'Hello' }], total: 1 }],\n         *   [['posts', 'getMany'], [{ id: 1, title: 'Hello' }]],\n         * ]","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/marmelab/react-admin/blob/051f511bb0afb5ea565c2d3728bf4dab0a6fa5e0/packages/ra-core/src/dataProvider/useMutationWithMutationMode.ts#L19-L55","documentation":"useMutationWithMutationMode is a generic wrapper around react-query's useMutation that handles optimistic/undoable modes. Its options must include a mutationFn describing the actual call; without one there is nothing to execute, so it throws at hook setup time rather than failing later inside react-query.","triggerScenarios":"Calling useMutationWithMutationMode({}) or omitting mutationFn in the options object; building options dynamically where mutationFn is conditionally spread; a typo like mutationfunction or fn instead of mutationFn.","commonSituations":"Abstracting mutation hooks where the mutationFn is expected to be injected but a caller forgot it; refactors that renamed mutationFn; conditional option assembly with spread of possibly-undefined objects.","solutions":["Always pass a mutationFn in options: useMutationWithMutationMode({ mutationFn: args => dataProvider.update(...), ... }).","If the fn is conditional, provide a fallback that rejects, or skip calling the hook.","Check option key spelling is exactly mutationFn."],"exampleFix":"// before\nuseMutationWithMutationMode({ mutationMode, onUndo });\n// after\nuseMutationWithMutationMode({ mutationMode, onUndo, mutationFn: ({ resource, params }) => dataProvider.update(resource, params) });","handlingStrategy":"validation","validationCode":"if (typeof options.mutationFn !== 'function') {\n  throw new TypeError('useMutationWithMutationMode: mutationFn is required');\n}","typeGuard":"const hasMutationFn = <T>(o: T & { mutationFn?: unknown }): o is T & { mutationFn: Function } =>\n  typeof o.mutationFn === 'function';","tryCatchPattern":"// thrown at render time by the hook; guard at the call site instead\nif (!hasMutationFn(options)) throw new TypeError('mutationFn missing');\nuseMutationWithMutationMode(options);","preventionTips":["Define mutationFn inline in the options object literal.","Avoid conditional spreads that may drop mutationFn.","Use TypeScript non-optional mutationFn in wrapper hook props."],"tags":["react-admin","mutation","missing-argument","react-query"],"backgroundTag":"missing-required-argument","analyzedSha":"051f511bb0afb5ea565c2d3728bf4dab0a6fa5e0","analyzedAt":"2026-08-30T02:28:14.926Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}