marmelab/react-admin · error

<BulkDeleteButton> components should be used inside a <Resou

Error message

<BulkDeleteButton> components should be used inside a <Resource> component or provided with a resource prop.

What it means

BulkDeleteButton performs a delete action scoped to a resource; it resolves the resource name via useResourceContext (from <ResourceContext>, a List context, or the resource prop). If no resource can be resolved, permission checks and the dataProvider call cannot be built, so it throws.

Source

Thrown at packages/ra-ui-materialui/src/button/BulkDeleteButton.tsx:48

 *     <List>
 *        <Datagrid bulkActionButtons={<PostBulkActionButtons />}>
 *             ...
 *       </Datagrid>
 *     </List>
 * );
 */
export const BulkDeleteButton = React.forwardRef(function BulkDeleteButton(
    inProps: BulkDeleteButtonProps,
    ref: React.ForwardedRef<HTMLButtonElement>
) {
    const { mutationMode = 'undoable', ...props } = useThemeProps({
        name: PREFIX,
        props: inProps,
    });

    const resource = useResourceContext(props);
    if (!resource) {
        throw new Error(
            '<BulkDeleteButton> components should be used inside a <Resource> component or provided with a resource prop.'
        );
    }
    const { canAccess, isPending } = useCanAccess({
        action: 'delete',
        resource,
    });
    if (!canAccess || isPending) {
        return null;
    }
    return mutationMode === 'undoable' ? (
        <BulkDeleteWithUndoButton ref={ref} {...props} />
    ) : (
        <BulkDeleteWithConfirmButton
            ref={ref}
            mutationMode={mutationMode}
            {...props}
        />

View on GitHub (pinned to 051f511bb0)

Solutions

  1. Pass the resource prop: <BulkDeleteButton resource="posts" />
  2. Render it inside a context providing the resource (List, ResourceContextProvider, DataTable selection context)
  3. If used inside custom bulk actions, forward the resource from the parent list

Example fix

// before
<MyToolbar><BulkDeleteButton /></MyToolbar>

// after
<ResourceContextProvider value="posts">
  <MyToolbar><BulkDeleteButton /></MyToolbar>
</ResourceContextProvider>
// or
<BulkDeleteButton resource="posts" />
Defensive patterns

Strategy: type-guard

Validate before calling

const resource = props.resource ?? currentResourceFromContext; // resolve before render
if (!resource) return null; // don't render BulkDeleteButton

Type guard

const hasResource = (p: { resource?: string }): p is { resource: string } =>
  typeof p.resource === 'string' && p.resource.length > 0;

Try / catch

try {
  return <BulkDeleteButton {...props} />;
} catch (e) {
  if (e.message.includes('BulkDeleteButton')) {
    return <BulkDeleteButton resource={fallbackResource} {...props} />;
  }
  throw e;
}

Prevention

When it happens

Trigger: Rendering <BulkDeleteButton /> outside a List/Datatable/Resource context without a resource prop; placing it in a custom toolbar or dashboard; composing bulk actions in a standalone component.

Common situations: Custom bulk action toolbars rendered outside <ListGuesser>/<DataTable> scope; refactors that moved the button out of the list; test setups mounting the button alone.

Related errors


AI-assisted analysis of marmelab/react-admin@051f511bb0 (2026-08-30). Data as JSON: /api/errors/818e176d77b44911. Report an issue: GitHub.