grafana/k6 · error
getting element's inner HTML
Error message
getting element's inner HTML: %w
What it means
ElementHandle.innerHTML() wraps the failure of a CDP evaluation that returns element.innerHTML by value. The read itself is cheap, so the wrapped error almost always means the evaluation could not run: the element handle is detached, the execution context was destroyed by navigation, the session closed, or the default timeout (30s) was exceeded.
Solutions
- Re-acquire the element handle immediately before reading innerHTML
- Wait for the page to be in a stable state: page.waitForLoadState() before reading
- Guard with await el.evaluate(e => e.isConnected) if the handle's freshness is uncertain
- Raise K6_BROWSER_TIMEOUT if the underlying cause is a stalled but recoverable session
Example fix
// before
const el = await page.$('#content');
await page.reload();
const html = await el.innerHTML(); // stale handle
// after
await page.reload();
const el = await page.$('#content');
const html = await el.innerHTML(); Defensive patterns
Strategy: try-catch
Validate before calling
// Read DOM state only from fresh, connected handles
const connected = await el.evaluate((e) => e.isConnected).catch(() => false);
if (!connected) throw new Error('stale handle; re-query before innerHTML()');
const html = await el.innerHTML(); Try / catch
try {
const html = await el.innerHTML();
} catch (e) {
if (/Could not find object|Execution context|timed out/i.test(String(e.message))) {
const html = await page.locator(sel).innerHTML(); // live re-resolve
} else throw e;
} Prevention
- Re-acquire handles after navigation or reload before asserting on DOM content
- Prefer locators over cached element handles for read-only assertions
- Finish DOM reads before triggering teardown (close/popups, navigation)
When it happens
Trigger: The page navigates between acquiring the handle and reading innerHTML; an SPA re-render detaches the node; the frame containing the element was closed; the browser/tab was closed mid-call; the CDP session stalled past the timeout.
Common situations: Caching element handles across page.goto() calls; reading DOM state from a page being torn down at iteration end; slow or overloaded browser sessions in CI.
Related errors
- focusing on element
- getting element's inner text
- dispatching element event
- getting attribute of element
- unexpected type %T (expecting string)
AI-assisted analysis of grafana/k6@3fcf5388d7 (2026-08-18).
Data as JSON: /api/errors/987a07e9bcd4409e.
Report an issue: GitHub.
Appendix: source
Thrown at internal/js/modules/k6/browser/common/element_handle.go:997
}
applySlowMo(h.ctx)
return nil
}
// InnerHTML returns the inner HTML of the element.
func (h *ElementHandle) InnerHTML() (string, error) {
innerHTML := func(apiCtx context.Context, handle *ElementHandle) (any, error) {
return handle.innerHTML(apiCtx)
}
opts := NewElementHandleBaseOptions(h.DefaultTimeout())
innerHTMLAction := h.newAction(
[]string{}, innerHTML, opts.Force, withRetry, opts.NoWaitAfter, opts.Timeout,
)
v, err := call(h.ctx, innerHTMLAction, opts.Timeout)
if err != nil {
return "", fmt.Errorf("getting element's inner HTML: %w", err)
}
applySlowMo(h.ctx)
s, ok := v.(string)
if !ok {
return "", fmt.Errorf("unexpected type %T (expecting string)", v)
}
return s, nil
}
// InnerText returns the inner text of the element.
func (h *ElementHandle) InnerText() (string, error) {
innerText := func(apiCtx context.Context, handle *ElementHandle) (any, error) {
return handle.innerText(apiCtx)
}
opts := NewElementHandleBaseOptions(h.DefaultTimeout())View on GitHub (pinned to 3fcf5388d7)