{"record":{"id":"090da6d408e5a61d","repo":"facebook/react","slug":"expected-to-find-root-id","errorCode":null,"errorMessage":"Expected to find root ID.","messagePattern":"Expected to find root ID\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/react-devtools-shared/src/backend/legacy/renderer.js","lineNumber":263,"sourceCode":"        // Remember the root.\n        internalInstanceToRootIDMap.set(\n          internalInstance,\n          getID(hostContainerInfo._topLevelWrapper),\n        );\n\n        try {\n          // $FlowFixMe[object-this-reference] found when upgrading Flow\n          const result = fn.apply(this, args);\n          parentIDStack.pop();\n          return result;\n        } catch (err) {\n          parentIDStack = [];\n          throw err;\n        } finally {\n          if (parentIDStack.length === 0) {\n            const rootID = internalInstanceToRootIDMap.get(internalInstance);\n            if (rootID === undefined) {\n              throw new Error('Expected to find root ID.');\n            }\n            flushPendingEvents(rootID);\n          }\n        }\n      },\n      performUpdateIfNecessary(fn, args) {\n        const internalInstance = args[0];\n        if (getElementType(internalInstance) === ElementTypeOtherOrUnknown) {\n          // $FlowFixMe[object-this-reference] found when upgrading Flow\n          return fn.apply(this, args);\n        }\n\n        const id = getID(internalInstance);\n        parentIDStack.push(id);\n\n        const prevChildren = getChildren(internalInstance);\n        try {\n          // $FlowFixMe[object-this-reference] found when upgrading Flow","sourceCodeStart":245,"sourceCodeEnd":281,"githubUrl":"https://github.com/facebook/react/blob/eafeac097ba51e1eab809c07102126bd5f8e5425/packages/react-devtools-shared/src/backend/legacy/renderer.js#L245-L281","documentation":"The React 15 backend decorates renderer.Reconciler.mountComponent to observe mounts. In the finally block, when parentIDStack empties (the top-level operation finished) it looks up the root id recorded for that instance in internalInstanceToRootIDMap - a WeakMap filled only when the decorated mountComponent observes the top-level wrapper. The throw means a mount completed at the top level for an instance whose root was never recorded: the tree started mounting before DevTools attached, or SSR markup bypassed the decorated path (the _topLevelWrapper SSR early-return at renderer.js:230-234).","triggerScenarios":"Attaching DevTools after the app already rendered, then any subsequent mount that finishes a top-level operation for pre-attach instances; or server-rendered React 15 markup whose client-side reconciliation reaches the finally block without a recorded root.","commonSituations":"Injecting DevTools late (bookmarklet, delayed extension load, dynamic import of react-devtools after render) into a React 15 app; hydrated React 15 pages; apps where the first user interaction triggers the first observed top-level mount.","solutions":["Load the DevTools hook before the app's React initializes (open DevTools first, or include the react-devtools hook script as the first tag) so every mount is observed.","Reload the page with DevTools already open - a fresh session records all roots.","Disable duplicate React extensions that may race attachment.","If embedding, wrap attach() and call the legacy backend's cleanup() when this error appears so the app is un-patched."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"// when embedding: if the legacy backend diverges, un-patch and let the app continue\ntry {\n  legacyRenderer.attach(hook, rendererID, renderer, global);\n} catch (err) {\n  if (err.message.includes('Expected to find root ID')) {\n  cleanupLegacyBackend(); // restore original Reconciler methods\n  } else {\n    throw err;\n  }\n}","preventionTips":["Load the DevTools hook before the app's React initializes (open DevTools first / hook script first in the document).","Never attach DevTools after a React 15 page has rendered - reload instead.","Disable other React extensions that change attach order."],"tags":["react-devtools","legacy-react","react-15","late-attach","root-tracking"],"backgroundTag":"missing-root-id","analyzedSha":"eafeac097ba51e1eab809c07102126bd5f8e5425","analyzedAt":"2026-08-21T22:01:08.818Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}