{"record":{"id":"818e176d77b44911","repo":"marmelab/react-admin","slug":"bulkdeletebutton-components-should-be-used-insid","errorCode":null,"errorMessage":"<BulkDeleteButton> components should be used inside a <Resource> component or provided with a resource prop.","messagePattern":"<BulkDeleteButton> components should be used inside a <Resource> component or provided with a resource prop\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/ra-ui-materialui/src/button/BulkDeleteButton.tsx","lineNumber":48,"sourceCode":" *     <List>\n *        <Datagrid bulkActionButtons={<PostBulkActionButtons />}>\n *             ...\n *       </Datagrid>\n *     </List>\n * );\n */\nexport const BulkDeleteButton = React.forwardRef(function BulkDeleteButton(\n    inProps: BulkDeleteButtonProps,\n    ref: React.ForwardedRef<HTMLButtonElement>\n) {\n    const { mutationMode = 'undoable', ...props } = useThemeProps({\n        name: PREFIX,\n        props: inProps,\n    });\n\n    const resource = useResourceContext(props);\n    if (!resource) {\n        throw new Error(\n            '<BulkDeleteButton> components should be used inside a <Resource> component or provided with a resource prop.'\n        );\n    }\n    const { canAccess, isPending } = useCanAccess({\n        action: 'delete',\n        resource,\n    });\n    if (!canAccess || isPending) {\n        return null;\n    }\n    return mutationMode === 'undoable' ? (\n        <BulkDeleteWithUndoButton ref={ref} {...props} />\n    ) : (\n        <BulkDeleteWithConfirmButton\n            ref={ref}\n            mutationMode={mutationMode}\n            {...props}\n        />","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/marmelab/react-admin/blob/051f511bb0afb5ea565c2d3728bf4dab0a6fa5e0/packages/ra-ui-materialui/src/button/BulkDeleteButton.tsx#L30-L66","documentation":"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.","triggerScenarios":"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.","commonSituations":"Custom bulk action toolbars rendered outside <ListGuesser>/<DataTable> scope; refactors that moved the button out of the list; test setups mounting the button alone.","solutions":["Pass the resource prop: <BulkDeleteButton resource=\"posts\" />","Render it inside a context providing the resource (List, ResourceContextProvider, DataTable selection context)","If used inside custom bulk actions, forward the resource from the parent list"],"exampleFix":"// before\n<MyToolbar><BulkDeleteButton /></MyToolbar>\n\n// after\n<ResourceContextProvider value=\"posts\">\n  <MyToolbar><BulkDeleteButton /></MyToolbar>\n</ResourceContextProvider>\n// or\n<BulkDeleteButton resource=\"posts\" />","handlingStrategy":"type-guard","validationCode":"const resource = props.resource ?? currentResourceFromContext; // resolve before render\nif (!resource) return null; // don't render BulkDeleteButton","typeGuard":"const hasResource = (p: { resource?: string }): p is { resource: string } =>\n  typeof p.resource === 'string' && p.resource.length > 0;","tryCatchPattern":"try {\n  return <BulkDeleteButton {...props} />;\n} catch (e) {\n  if (e.message.includes('BulkDeleteButton')) {\n    return <BulkDeleteButton resource={fallbackResource} {...props} />;\n  }\n  throw e;\n}","preventionTips":["Always render bulk buttons within List/DataTable scope","Pass resource explicitly in shared toolbars","Wrap standalone usage in ResourceContextProvider","Audit custom bulk action components for missing resource context after refactors"],"tags":["react-admin","resource-context","missing-prop","button"],"backgroundTag":"missing-resource-context","analyzedSha":"051f511bb0afb5ea565c2d3728bf4dab0a6fa5e0","analyzedAt":"2026-08-30T02:28:14.926Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}