grafana/k6 · error

calling function: %w

Error message

calling function: %w

What it means

Thrown by Frame.runActionOnSelector when the query succeeded and a handle was found, but the element action itself (fn(ctx, handle) — the click/type/focus implementation) returned an error. The wrapped error typically comes from CDP: element not visible, not stable, detached during action, or the browser refused the input (for example intercepted by an overlay).

Source

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

	// id returns the CDP runtime ID of this execution context.
	ID() runtime.ExecutionContextID
}

func (f *Frame) runActionOnSelector(
	ctx context.Context, selector string, strict bool, fn elementHandleActionFunc, nullResponder func() bool,
) (bool, error) {
	handle, err := f.Query(selector, strict)
	if err != nil {
		return false, fmt.Errorf("query: %w", err)
	}
	if handle == nil {
		f.log.Debugf("Frame:runActionOnSelector:nilHandler", "fid:%s furl:%q selector:%s", f.ID(), f.URL(), selector)
		return nullResponder(), err
	}

	v, err := fn(ctx, handle)
	if err != nil {
		return false, fmt.Errorf("calling function: %w", err)
	}

	bv, ok := v.(bool)
	if !ok {
		return false, fmt.Errorf("unexpected type %T", v)
	}

	return bv, nil
}

//nolint:unparam
func (f *Frame) newAction(
	selector string, state DOMElementState, strict bool, fn elementHandleActionFunc, states []string,
	force bool, retry bool, noWaitAfter bool, timeout time.Duration,
) func(apiCtx context.Context, resultCh chan any, errCh chan error) {
	// We execute a frame action in the following steps:
	// 1. Find element matching specified selector
	// 2. Wait for it to reach specified DOM state

View on GitHub (pinned to 93accf6570)

Solutions

  1. Wait for the element to be actionable: page.waitForSelector(sel, { state: 'visible' }) before the action
  2. Retry the action — transient detach during SPA rerender usually succeeds on a second attempt with a fresh selector call
  3. If an overlay legitimately intercepts, use { force: true } to bypass actionability checks
  4. Stabilize the app under test (disable animations) rather than fighting the checks

Example fix

// before
await page.click('#save'); // hidden behind a cookie banner

// after
await page.waitForSelector('#save', { state: 'visible' });
await page.click('#save', { timeout: 30_000 });
// or bypass overlays when intentional: page.click('#save', { force: true })
Defensive patterns

Strategy: retry

Type guard

function isActionFailure(e) {
  return e instanceof Error && /calling function/.test(e.message);
}

Try / catch

async function clickStable(page, sel, tries = 3) {
  for (let i = 0; i < tries; i++) {
    try {
      await page.waitForSelector(sel, { state: 'visible' });
      return await page.click(sel);
    } catch (e) { if (i === tries - 1) throw e; }
  }
}

Prevention

When it happens

Trigger: page.click(sel) on an element with zero size or display:none; element re-rendered (detached) between query and action; overlay/toaster intercepting the pointer; page navigating mid-click; actionability checks failing because the element keeps moving.

Common situations: Animated buttons (hover effects, sticky headers); SPAs that re-render on every state change invalidating handles; CI headless environments where layout differs; clicking before fonts/layout settle.

Related errors


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