grafana/k6 · error · ErrElementNotAttachedToDOM
element is not attached to the DOM
Error message
element is not attached to the DOM
What it means
Sentinel error ErrElementNotAttachedToDOM from the k6 browser (chromium) module. It means the ElementHandle's backing DOM node no longer exists in the document: the node was removed by script, replaced by a re-render, or its frame navigated away. Operations like boundingBox(), click(), or element-state waits return it instead of acting on a dead reference, and the mapping layer (element_handle_mapping.go:22, locator_mapping.go:42) treats it as a retryable action failure.
Source
Thrown at internal/js/modules/k6/browser/common/element_handle.go:28
"slices"
"strconv"
"strings"
"time"
"github.com/chromedp/cdproto/cdp"
"github.com/chromedp/cdproto/dom"
"go.opentelemetry.io/otel/attribute"
"go.k6.io/k6/v2/internal/js/modules/k6/browser/common/js"
"go.k6.io/k6/v2/internal/js/modules/k6/browser/k6ext"
)
// Common error types for element visibility.
var (
// ErrElementNotVisible is returned when an element is not visible for an operation.
ErrElementNotVisible = errors.New("element is not visible")
// ErrElementNotAttachedToDOM is returned when an element is not attached to the DOM.
ErrElementNotAttachedToDOM = errors.New("element is not attached to the DOM")
)
const (
resultDone = "done"
resultNeedsInput = "needsinput"
)
type (
elementHandleActionFunc func(context.Context, *ElementHandle) (any, error)
elementHandlePointerActionFunc func(context.Context, *ElementHandle, *Position) (any, error)
retryablePointerActionFunc func(context.Context, *ScrollIntoViewOptions) (any, error)
// evalFunc is a common interface for both evalWithScript and eval.
// It helps abstracting these methods to aid with testing.
evalFunc func(ctx context.Context, opts evalOptions, js string, args ...any) (any, error)
)
// ElementHandle represents a HTML element JS object inside an execution context.View on GitHub (pinned to 93accf6570)
Solutions
- Re-query the element (page.$ or page.waitForSelector) immediately before the action instead of reusing an old handle
- Prefer the Locator API (page.locator(...).click()), which re-resolves the element on each retry
- Call page.waitForLoadState('load') or waitForNavigation first so the DOM is stable before querying
- Wrap the action in try-catch and on this error retry the whole query+action sequence once
Example fix
// before
const btn = await page.$('#submit');
await page.goto('https://example.com/next');
await btn.click(); // handle is stale
// after
await page.goto('https://example.com/next');
const btn = await page.waitForSelector('#submit');
await btn.click(); Defensive patterns
Strategy: retry
Validate before calling
// Check the node is still connected before acting on a stored handle
const attached = await handle.evaluate(el => el.isConnected);
if (!attached) {
handle = await page.waitForSelector(selector, { state: 'visible' });
}
await handle.click(); Try / catch
try {
await handle.click();
} catch (e) {
if (String(e.message).includes('not attached')) {
handle = await page.waitForSelector(selector); // re-query
await handle.click(); // one retry with the fresh handle
} else { throw e; }
} Prevention
- Prefer locators (page.locator(...)) over stored ElementHandles — they re-resolve on each attempt
- Never reuse handles across navigations; re-query after every goto/waitForNavigation
- Query elements only after the page load state has settled
When it happens
Trigger: Calling ElementHandle or Locator actions (click, fill, check, waitForElementState, boundingBox) on a handle whose node was already removed; CDP returns 'error:notconnected' or an empty box model (element_handle.go:63-73, 1885, 1892); the element is replaced by an SPA re-render between the query and the action; the frame holding the element navigates and destroys the execution context.
Common situations: React/Vue apps replacing keyed nodes on re-render; handles captured early and used after the page changed; interacting while navigation is still settling; iframes removed mid-action.
Related errors
- getting document element: nil document
- getting node in frame: %w
- selecting text: %w
- setting input files: %w
- getting text content of element: %w
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/b9f43a54570bbc87.
Report an issue: GitHub.