grafana/k6 · error
getting element position
Error message
getting element position: %w
What it means
Stage of the k6 browser module's pointer-action pipeline that runs when opts.Position is set: offsetPosition computes the absolute click/tap point from the user-supplied offset relative to the element. This error wraps that computation failing — typically because the element's bounding box could not be obtained (hidden, no layout, detached) or the containing element is not queryable.
Solutions
- Wait for the element to be visible and have a size: waitForSelector(sel, { state: 'visible' }) and confirm via el.boundingBox() in a retry loop if needed.
- Verify the offset lies within the element's current bounding box; recompute from el.boundingBox() rather than hardcoding.
- Set an explicit viewport matching the layout the offsets were designed for.
- Drop the custom position and click the center if the spot does not matter.
Example fix
// before
const el = await page.$('#map');
await el.click({ position: { x: 320, y: 240 } }); // map not rendered yet -> no box
// after
const el = await page.waitForSelector('#map', { state: 'visible' });
const box = await el.boundingBox();
if (box && box.width > 0) {
await el.click({ position: { x: Math.min(320, box.width - 1), y: Math.min(240, box.height - 1) } });
} 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 rendered box; cannot use position offset');
}
const x = Math.min(offsetX, box.width - 1);
const y = Math.min(offsetY, box.height - 1);
await el.click({ position: { x, y } }); Type guard
async function hasUsableBox(el) {
const b = await el.boundingBox().catch(() => null);
return !!b && b.width > 0 && b.height > 0;
} Try / catch
try {
await el.click({ position: { x: offsetX, y: offsetY }, timeout: '30s' });
} catch (e) {
if (String(e).includes('getting element position')) {
await el.click(); // fall back to center click
} else { throw e; }
} Prevention
- Derive offsets from el.boundingBox() instead of hardcoding pixels.
- Pin the viewport so responsive layouts keep coordinates stable.
When it happens
Trigger: click({ position: { x: 10, y: 10 } }) or tap({ position }) on an element whose bounding box cannot be resolved at action time — display:none, zero-size, detached — or with offsets outside the element's box on a re-rendered node.
Common situations: Clicking a specific spot on a canvas/map/image that is lazily rendered or resized at action time; offsets tuned against a different viewport than the test's (responsive layouts shift coordinates).
Related errors
- checking hit target
- pointer action
- translating point to page
- waiting for element state
- getting injected script
AI-assisted analysis of grafana/k6@3fcf5388d7 (2026-08-18).
Data as JSON: /api/errors/0de9eacbe078e5e5.
Report an issue: GitHub.
Appendix: source
Thrown at internal/js/modules/k6/browser/common/element_handle.go:1746
}
err = h.scrollRectIntoViewIfNeeded(apiCtx, rect)
} else {
_, err = h.eval(
apiCtx,
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 {View on GitHub (pinned to 3fcf5388d7)