{"record":{"id":"141dc72996d8401f","repo":"microsoft/playwright","slug":"element-is-not-attached-to-the-dom","errorCode":null,"errorMessage":"Element is not attached to the DOM","messagePattern":"Element is not attached to the DOM","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/playwright-core/src/server/dom.ts","lineNumber":971,"sourceCode":"      // Hit target in the parent frame should hit the child frame element.\n      const hitTargetResult = await progress.race(element.evaluateInUtility(([injected, element, hitPoint]) => {\n        return injected.expectHitTarget(hitPoint, element);\n      }, point));\n      if (hitTargetResult !== 'done')\n        return hitTargetResult;\n    }\n    return { framePoint: data[0].pointInFrame };\n  }\n}\n\nexport function throwRetargetableDOMError<T>(result: T | 'error:notconnected'): T {\n  if (result === 'error:notconnected')\n    throwElementIsNotAttached();\n  return result;\n}\n\nexport function throwElementIsNotAttached(): never {\n  throw new Error('Element is not attached to the DOM');\n}\n\nexport function assertDone(result: 'done'): void {\n  // This function converts 'done' to void and ensures typescript catches unhandled errors.\n}\n\nfunction roundPoint(point: types.Point): types.Point {\n  return {\n    x: (point.x * 100 | 0) / 100,\n    y: (point.y * 100 | 0) / 100,\n  };\n}\n\nfunction quadToRect(quad: types.Quad): types.Rect {\n  let minX = Infinity;\n  let minY = Infinity;\n  let maxX = -Infinity;\n  let maxY = -Infinity;","sourceCodeStart":953,"sourceCodeEnd":989,"githubUrl":"https://github.com/microsoft/playwright/blob/c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6/packages/playwright-core/src/server/dom.ts#L953-L989","documentation":"An element handle references a DOM node that has since been removed from the document (the injected utility returned 'error:notconnected'). throwElementIsNotAttached converts that into Error('Element is not attached to the DOM'). ElementHandle is a snapshot pointer; once the node is removed/re-rendered the handle is stale and any action on it fails.","triggerScenarios":"Querying an ElementHandle, then after a re-render or navigation the node is replaced, then calling an action on the old handle; React/Vue re-rendering a list item so the old node is discarded; SPA route change that replaces the container.","commonSituations":"Storing element handles across awaits in React/Vue apps; acting on a handle obtained before an animation that swaps nodes; navigating away and back so the original nodes are new instances.","solutions":["Use Locators instead of ElementHandle — Locators re-resolve the element on every action and stay valid across re-renders.","Re-query the element handle immediately before the action if you must use handles.","Await stability (waitFor selector / waitForLoadState) so re-renders settle before acting.","Avoid caching handles from beforeEach across the test body."],"exampleFix":"// before — stale handle\nconst handle = await page.$('#item');\nawait page.reload();\nawait handle.click(); // node gone → throws\n// after — locator re-resolves\nconst item = page.locator('#item');\nawait page.reload();\nawait item.click();","handlingStrategy":"retry","validationCode":"// Use a Locator so the element is re-resolved on each action.\nconst item = page.locator('#item');\nawait page.reload();\nawait item.click(); // re-queries after reload","typeGuard":null,"tryCatchPattern":"// If you must use a handle, re-query on staleness.\nasync function clickFresh(page: Page, selector: string) {\n  try {\n    await (await page.$(selector))?.click();\n  } catch (e) {\n    if (e.message.includes('not attached to the DOM')) {\n      await (await page.$(selector))?.click(); // re-query and retry once\n    } else throw e;\n  }\n}","preventionTips":["Prefer Locators over ElementHandle — they re-resolve automatically.","Do not cache element handles across navigations or re-renders.","Await load-state/stability before acting to let re-renders settle."],"tags":["dom","staleness","detached","element-handle"],"backgroundTag":null,"analyzedSha":"c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6","analyzedAt":"2026-08-12T07:26:36.950Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}