{"record":{"id":"a8d5c05367e2336d","repo":"testing-library/react-testing-library","slug":"attempted-to-hydrate-a-non-hydrateable-root-this","errorCode":null,"errorMessage":"Attempted to hydrate a non-hydrateable root. This is a bug in `@testing-library/react`.","messagePattern":"Attempted to hydrate a non-hydrateable root\\. This is a bug in `@testing-library/react`\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/pure.js","lineNumber":136,"sourceCode":"        strictModeIfNeeded(\n          wrapUiIfNeeded(ui, WrapperComponent),\n          reactStrictMode,\n        ),\n        {onCaughtError, onRecoverableError},\n      )\n    })\n  } else {\n    root = ReactDOMClient.createRoot(container, {\n      onCaughtError,\n      onRecoverableError,\n    })\n  }\n\n  return {\n    hydrate() {\n      /* istanbul ignore if */\n      if (!hydrate) {\n        throw new Error(\n          'Attempted to hydrate a non-hydrateable root. This is a bug in `@testing-library/react`.',\n        )\n      }\n      // Nothing to do since hydration happens when creating the root object.\n    },\n    render(element) {\n      root.render(element)\n    },\n    unmount() {\n      root.unmount()\n    },\n  }\n}\n\nfunction createLegacyRoot(container) {\n  return {\n    hydrate(element) {\n      ReactDOM.hydrate(element, container)","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/testing-library/react-testing-library/blob/20ce75f2907ca0e5c5a8ae595c0e9a4e368c7800/src/pure.js#L118-L154","documentation":"In createConcurrentRoot (src/pure.js), the returned root object exposes a hydrate() method that is only meaningful when the root was created via hydrateRoot. If the internal `hydrate` flag is false the root was built with createRoot, so calling hydrate() throws. The message says 'This is a bug in `@testing-library/react`' because the library itself should never call hydrate on a non-hydrateable root; users cannot normally trigger it through the public API.","triggerScenarios":"renderRoot calls root.hydrate() on a root object produced by createConcurrentRoot with hydrate: false (i.e. render() was called without {hydrate: true}), a state inconsistency inside the library.","commonSituations":"Practically only seen when a custom wrapper or patched internals of @testing-library/react mix hydrated and non-hydrated roots, or when passing an externally created root object into renderRoot with mismatched options.","solutions":["Pass {hydrate: true} to render() if you intend to hydrate server-rendered markup, so the root is created with hydrateRoot.","Do not call (or trigger) hydrate() on a root created without the hydrate option; use render() instead.","If it appears without custom code, report it as a bug to @testing-library/react with a reproduction.","Verify you are not mixing roots created by different render() calls (hydrated vs non-hydrated) in a custom wrapper."],"exampleFix":"// before\nrender(<App />, { container })\nroot.hydrate()\n// after\nrender(<App />, { container, hydrate: true })","handlingStrategy":"validation","validationCode":"// Only trigger hydration when you opted in\nconst options = isServerMarkup ? { hydrate: true } : {}\nrender(<App />, options)","typeGuard":"function canHydrate(renderOptions) {\n  return typeof renderOptions === 'object' && renderOptions !== null && renderOptions.hydrate === true\n}","tryCatchPattern":"try {\n  render(<App />, { hydrate: true })\n} catch (e) {\n  if (String(e.message).includes('non-hydrateable root')) {\n    // retry as a plain client render\n    render(<App />)\n  } else {\n    throw e\n  }\n}","preventionTips":["Only set hydrate: true when the container actually contains server-rendered HTML.","Never call internal root.hydrate() methods yourself; use the public render() API.","Keep @testing-library/react updated; this error is flagged as an internal bug by the library itself.","Do not reuse root objects across hydrated and non-hydrated render calls."],"tags":["hydration","react","ssr","internal-bug"],"backgroundTag":"hydration-mismatch","analyzedSha":"20ce75f2907ca0e5c5a8ae595c0e9a4e368c7800","analyzedAt":"2026-09-02T16:11:03.216Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T21:17:11.164Z"}