{"record":{"id":"3e0d93ab990238ae","repo":"tailwindlabs/headlessui","slug":"you-provided-an-open-prop-to-the-dialog-but-f","errorCode":null,"errorMessage":"You provided an `open` prop to the `Dialog`, but forgot an `onClose` prop.","messagePattern":"You provided an `open` prop to the `Dialog`, but forgot an `onClose` prop\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/@headlessui-react/src/components/dialog/dialog.tsx","lineNumber":399,"sourceCode":"  // Validations\n  let usesOpenClosedState = useOpenClosed()\n  let hasOpen = props.hasOwnProperty('open') || usesOpenClosedState !== null\n  let hasOnClose = props.hasOwnProperty('onClose')\n\n  if (!hasOpen && !hasOnClose) {\n    throw new Error(\n      `You have to provide an \\`open\\` and an \\`onClose\\` prop to the \\`Dialog\\` component.`\n    )\n  }\n\n  if (!hasOpen) {\n    throw new Error(\n      `You provided an \\`onClose\\` prop to the \\`Dialog\\`, but forgot an \\`open\\` prop.`\n    )\n  }\n\n  if (!hasOnClose) {\n    throw new Error(\n      `You provided an \\`open\\` prop to the \\`Dialog\\`, but forgot an \\`onClose\\` prop.`\n    )\n  }\n\n  if (!usesOpenClosedState && typeof props.open !== 'boolean') {\n    throw new Error(\n      `You provided an \\`open\\` prop to the \\`Dialog\\`, but the value is not a boolean. Received: ${props.open}`\n    )\n  }\n\n  if (typeof props.onClose !== 'function') {\n    throw new Error(\n      `You provided an \\`onClose\\` prop to the \\`Dialog\\`, but the value is not a function. Received: ${props.onClose}`\n    )\n  }\n\n  if ((open !== undefined || transition) && !rest.static) {\n    return (","sourceCodeStart":381,"sourceCodeEnd":417,"githubUrl":"https://github.com/tailwindlabs/headlessui/blob/eea57cf46fd6767ed1059012f7073b88eb159fba/packages/@headlessui-react/src/components/dialog/dialog.tsx#L381-L417","documentation":"The inverse validation: `open` was provided but `onClose` was not (and no OpenClosed context). Dialog needs a callback to signal close requests (Escape key, backdrop click, scroll-lock teardown); without it the dialog would be impossible to dismiss, so it throws.","triggerScenarios":"`<Dialog open={isOpen}>` with no `onClose`; passing onClose via a spread that evaluates undefined; renaming the handler (e.g., `onCloseRequest`) so the real prop is missing.","commonSituations":"Initial scaffolding where only `open` was wired; prop drilling typos; using `onRequestClose` (react-native-modal naming) instead of `onClose`.","solutions":["Add `<Dialog open={open} onClose={() => setOpen(false)}>`.","If you truly want it non-dismissible, still pass a no-op: `onClose={() => {}}` and disable outside-click/escape via `static` + custom handling.","Verify spreads: `<Dialog open={open} {...rest}>` where rest actually contains onClose."],"exampleFix":"// before\n<Dialog open={isOpen}>...</Dialog>\n\n// after\n<Dialog open={isOpen} onClose={() => setIsOpen(false)}>...</Dialog>","handlingStrategy":"type-guard","validationCode":"const close = useCallback(() => setOpen(false), [])\n// <Dialog open={open} onClose={close}>","typeGuard":"const hasOnClose = (p: { onClose?: unknown }): boolean => typeof p.onClose === 'function'","tryCatchPattern":null,"preventionTips":["Pair open and onClose in one reusable snippet.","Use exactly the prop name onClose, not onRequestClose.","Provide a no-op onClose if dismissal must be disabled."],"tags":["headlessui","react","dialog","controlled-component","missing-prop"],"backgroundTag":"missing-required-prop","analyzedSha":"eea57cf46fd6767ed1059012f7073b88eb159fba","analyzedAt":"2026-08-28T19:22:46.163Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}