refinedev/refine · error · Error

Not implemented custom on data provider.

Error message

Not implemented custom on data provider.

What it means

Thrown inside `useCustomMutation`'s mutationFn in @refinedev/core when the resolved data provider has no `custom` method. The hook's mutation function tries `dataProvider.custom(...)`; if the method is absent, execution falls through to `throw Error("Not implemented custom on data provider.")`, which surfaces as a rejected mutation error in react-query.

Source

Thrown at packages/core/src/hooks/data/useCustomMutation.ts:162

      config,
    }: useCustomMutationParams<TData, TError, TVariables>) => {
      const combinedMeta = getMeta({
        meta: meta,
      });

      const { custom } = dataProvider(dataProviderName);

      if (custom) {
        return custom<TData>({
          url,
          method,
          payload: values,
          meta: combinedMeta,
          headers: { ...config?.headers },
        });
      }

      throw Error("Not implemented custom on data provider.");
    },
    onSuccess: (data, variables, context) => {
      const {
        successNotification: successNotificationFromProp,
        config,
        meta,
      } = variables;

      const notificationConfig =
        typeof successNotificationFromProp === "function"
          ? successNotificationFromProp(data, {
              ...config,
              ...(meta || {}),
            })
          : successNotificationFromProp;

      handleNotification(notificationConfig);

View on GitHub (pinned to 779d52a20e)

Solutions

  1. Add a `custom` implementation to your custom data provider delegating to fetch/your SDK
  2. Use a provider that supports custom for this operation via dataProviderName
  3. Replace with a direct mutation using useMutation + fetch/SDK

Example fix

// before (component with appwrite provider)
const { mutate } = useCustomMutation({ url: '/notify', method: 'post' });
// after
const { mutate } = useMutation({
  mutationFn: (payload) => fetch('/notify', {
    method: 'POST',
    body: JSON.stringify(payload),
  }),
});
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof dataProvider.custom !== 'function') {
  // wire useMutation + fetch instead of useCustomMutation
}

Type guard

const supportsCustom = (dp: unknown): dp is { custom: (o: any) => Promise<any> } =>
  typeof (dp as any)?.custom === 'function';

Try / catch

useCustomMutation(...).mutate(payload, {
  onError: (e) => {
    if (/Not implemented custom/.test(e.message)) useDirectMutation(payload);
    else throw e;
  },
});

Prevention

When it happens

Trigger: Invoking `mutate()` from `useCustomMutation({ url, method: 'post', values })` where the active (or named) data provider does not implement `custom` — e.g. airtable, appwrite, or a hand-rolled provider missing the optional method.

Common situations: Copy-pasting a useCustomMutation call (webhook trigger, custom endpoint POST) into an app whose provider doesn't support it; custom in-house providers that only implemented the required CRUD methods.

Related errors


AI-assisted analysis of refinedev/refine@779d52a20e (2026-08-27). Data as JSON: /api/errors/7b2733136b1775ec. Report an issue: GitHub.