grafana/k6 · error

getting bounding box of %q: unexpected type %T

Error message

getting bounding box of %q: unexpected type %T

What it means

After the wait-for-selector action succeeds, Frame.BoundingBox() asserts that the action's return value is a *Rect (produced by ElementHandle.BoundingBox()). If the internal pipeline returned nil or any other Go type, this type assertion fails. This is an internal invariant violation of the k6 browser module, not a user-input error: normally the DOM action returns a Rect or errors out before this line.

Source

Thrown at internal/js/modules/k6/browser/common/frame.go:586

	return handle, err
}

func (f *Frame) boundingBox(selector string, opts *FrameBaseOptions) (*Rect, error) {
	getBoundingBox := func(apiCtx context.Context, handle *ElementHandle) (any, error) {
		return handle.BoundingBox()
	}
	act := f.newAction(
		selector, DOMElementStateAttached, opts.Strict, getBoundingBox, []string{}, false, noRetry, true, opts.Timeout,
	)
	v, err := call(f.ctx, act, opts.Timeout)
	if err != nil {
		return nil, errorFromDOMError(err)
	}

	bv, ok := v.(*Rect)
	if !ok {
		return nil, fmt.Errorf("getting bounding box of %q: unexpected type %T", selector, v)
	}

	return bv, nil
}

// ChildFrames returns a list of child frames.
func (f *Frame) ChildFrames() []*Frame {
	f.childFramesMu.RLock()
	defer f.childFramesMu.RUnlock()

	l := make([]*Frame, 0, len(f.childFrames))
	for child := range f.childFrames {
		l = append(l, child)
	}
	return l
}

// Click clicks the first element found that matches selector.

View on GitHub (pinned to 93accf6570)

Solutions

  1. Retry after ensuring the element is stable: await page.waitForSelector(sel, { state: 'visible' }) before boundingBox().
  2. If it repeats on the same element, check the element actually has layout (not display:none / detached) — try frame.evaluate on getBoundingClientRect to compare.
  3. Upgrade to the latest k6 — this code path is internal and such assertion failures have historically been module bugs.
  4. If persistent, report it with a minimal reproducing script at the k6-browser GitHub issues.

Example fix

// before
const rect = page.boundingBox('#cart-icon');

// after
await page.waitForSelector('#cart-icon', { state: 'visible' });
const rect = await (async () => {
  try {
    return page.boundingBox('#cart-icon');
  } catch (e) {
    console.warn('boundingBox failed, element may have detached:', e.message);
    return null;
  }
})();
Defensive patterns

Strategy: try-catch

Validate before calling

await page.waitForSelector(sel, { state: 'visible', timeout: 30000 });

Type guard

const isRect = (r) => r != null && typeof r === 'object' && ['x','y','width','height'].every((k) => typeof r[k] === 'number');

Try / catch

try {
  const rect = page.boundingBox(sel);
  if (!isRect(rect)) throw new Error('boundingBox returned non-rect');
} catch (e) {
  console.warn('boundingBox failed:', e.message);
}

Prevention

When it happens

Trigger: Calling frame.boundingBox(selector) (or page.boundingBox) where handle.BoundingBox() returns nil — e.g. the element detaches between the successful wait and the bounding-box CDP call, or the element renders with no layout box (display:none subtree edge cases). Also possible after internal refactors that change the action's return type.

Common situations: Element removed/re-rendered by the SPA right after becoming visible; shadow-DOM or zero-size elements; a regression in the k6 browser module after upgrading k6 (internal type changed); intermittent only under load timing.

Related errors


AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15). Data as JSON: /api/errors/ee5142637e331b51. Report an issue: GitHub.