{"record":{"id":"304029b73df6c11f","repo":"facebook/react","slug":"257","errorCode":"257","errorMessage":"Portals are not currently supported by the server renderer. Render them conditionally so that they only appear on the client render.","messagePattern":"Portals are not currently supported by the server renderer\\. Render them conditionally so that they only appear on the client render\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/react-server/src/ReactFizzServer.js","lineNumber":3578,"sourceCode":"            debugTask.run(\n              renderElement.bind(\n                null,\n                request,\n                task,\n                keyPath,\n                type,\n                props,\n                ref,\n              ),\n            );\n          } else {\n            renderElement(request, task, keyPath, type, props, ref);\n          }\n        }\n        return;\n      }\n      case REACT_PORTAL_TYPE:\n        throw new Error(\n          'Portals are not currently supported by the server renderer. ' +\n            'Render them conditionally so that they only appear on the client render.',\n        );\n      case REACT_LAZY_TYPE: {\n        const lazyNode: LazyComponentType<any, any> = node as any;\n        let resolvedNode;\n        if (__DEV__) {\n          resolvedNode = callLazyInitInDEV(lazyNode);\n        } else {\n          const payload = lazyNode._payload;\n          const init = lazyNode._init;\n          resolvedNode = init(payload);\n        }\n        if (request.aborted) {\n          // eslint-disable-next-line no-throw-literal\n          throw null;\n        }\n        // Now we render the resolved node","sourceCodeStart":3560,"sourceCodeEnd":3596,"githubUrl":"https://github.com/facebook/react/blob/eafeac097ba51e1eab809c07102126bd5f8e5425/packages/react-server/src/ReactFizzServer.js#L3560-L3596","documentation":"Fizz's renderNodeDestructive throws immediately (error code 257) for REACT_PORTAL_TYPE elements: portals need a live DOM target node, which does not exist during server rendering.","triggerScenarios":"Rendering the return value of ReactDOM.createPortal(...) during SSR; a shared modal/tooltip/menu component that unconditionally mounts a portal in its render output.","commonSituations":"Design-system overlays used inside server-rendered trees; components run through renderToString/renderToStaticMarkup in tests; forgetting that SSR has no document object.","solutions":["Mount portals only on the client: render them after mount (useEffect plus a mounted flag) or behind a typeof document check","Return null for the overlay during SSR and let the client hydrate/mount it","Mark the portal-hosting component 'use client' and mount it after hydration"],"exampleFix":"// before\nfunction Modal({children}) {\n  return ReactDOM.createPortal(children, document.body); // throws during SSR\n}\n\n// after\nfunction Modal({children}) {\n  const [mounted, setMounted] = useState(false);\n  useEffect(() => setMounted(true), []);\n  if (!mounted) return null; // no portal on the server\n  return ReactDOM.createPortal(children, document.body);\n}","handlingStrategy":"fallback","validationCode":"const canUseDOM = typeof document !== 'undefined';\n// render portal subtrees only when canUseDOM is true\nreturn canUseDOM ? ReactDOM.createPortal(children, document.body) : null;","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never touch document during render; do DOM work in effects","Assume every component may be server rendered; guard DOM-only APIs","Mount overlays after a mounted flag flips in useEffect"],"tags":["portal","ssr","dom","modal"],"backgroundTag":"portal-unsupported-in-ssr","analyzedSha":"eafeac097ba51e1eab809c07102126bd5f8e5425","analyzedAt":"2026-08-21T22:01:08.818Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}