grafana/k6 · error
pointer action
Error message
pointer action: %w
What it means
Stage of the k6 browser module's pointer-action pipeline that resolves the element's clickable point when no custom position was given: clickablePoint() reads the element's BoundingBox and takes its center. This error (labelled 'pointer action') wraps that failing — the inner error is 'finding clickable point', caused by a missing bounding box (hidden element, zero-size element, detached node, or element inside an unrendered iframe).
Solutions
- Wait until the element has actual size: waitForSelector(sel, { state: 'visible' }) plus (if needed) a boundingBox retry loop checking width/height > 0.
- Await font/image load: page.waitForLoadState('networkidle') before acting.
- Re-query the handle right before the click to avoid detachment races.
- If the element is intentionally zero-size, click a positioned parent or use { position } on an ancestor with a real box.
Example fix
// before
const el = await page.$('#icon-button');
await el.click(); // zero-size until icon font loads
// after
await page.waitForLoadState('networkidle');
const el = await page.waitForSelector('#icon-button', { state: 'visible' });
await el.click(); Defensive patterns
Strategy: validation
Validate before calling
const box = await el.boundingBox();
if (!box || box.width <= 0 || box.height <= 0) {
throw new Error(`element has no clickable box (${JSON.stringify(box)})`);
}
await el.click(); Type guard
async function isClickable(el) {
const b = await el.boundingBox().catch(() => null);
return !!b && b.width > 0 && b.height > 0;
} Try / catch
try {
await el.click();
} catch (e) {
if (String(e).includes('pointer action')) {
await page.waitForLoadState('networkidle');
el = await page.waitForSelector(sel, { state: 'visible' });
await el.click();
} else { throw e; }
} Prevention
- Wait for fonts/images to load before clicking layout-dependent elements.
- For zero-size hooks, click a sized parent instead.
When it happens
Trigger: click()/dblclick()/hover() without position on an element with no rendered box: display:none, width/height 0 (e.g., an empty inline element), an <svg> or custom element not yet upgraded, or a node detached after passing earlier checks.
Common situations: Clicking placeholder elements before content renders; zero-size anchors used as JS hooks; elements that only get size after fonts/images load (CLS); virtualized list rows unmounted mid-action.
Related errors
- checking hit target
- getting element position
- translating point to page
- waiting for element state
- getting bounding box of parent frame
AI-assisted analysis of grafana/k6@3fcf5388d7 (2026-08-18).
Data as JSON: /api/errors/989a01b9ac01c74a.
Report an issue: GitHub.
Appendix: source
Thrown at internal/js/modules/k6/browser/common/element_handle.go:1751
evalOptions{forceCallable: true, returnByValue: false},
js.ScrollIntoView,
sopts,
)
}
if err != nil {
return nil, fmt.Errorf("scrolling element into view: %w", err)
}
// Get the clickable point
if p != nil {
p, err = h.offsetPosition(apiCtx, opts.Position)
if err != nil {
return nil, fmt.Errorf("getting element position: %w", err)
}
} else {
p, err = h.clickablePoint()
if err != nil {
return nil, fmt.Errorf("pointer action: %w", err)
}
}
// Further translation of the point might be necessary if the point
// is still relative to the parent frame it is in and not the page.
*p, err = h.translatePointToPage(apiCtx, *p)
if err != nil {
return nil, fmt.Errorf("translating point to page: %w", err)
}
// Do a final actionability check to see if element can receive events
// at mouse position in question
if !opts.Force {
if ok, err := h.checkHitTargetAt(apiCtx, *p); !ok {
return nil, fmt.Errorf("checking hit target: %w", err)
}
}
// Are we only "trialing" the action but not actually performingView on GitHub (pinned to 3fcf5388d7)