grafana/k6 · error

getting attribute %q of element: %w

Error message

getting attribute %q of element: %w

What it means

Returned by ElementHandle.getAttribute(name) when the underlying evaluation fails. Internally the method evaluates element.getAttribute(name) via CDP with returnByValue; this error wraps a CDP/transport failure, a stale handle, or a timeout. Note that a missing attribute is NOT an error: in that case the method returns ("", false, nil) with no error.

Source

Thrown at internal/js/modules/k6/browser/common/element_handle.go:955

	applySlowMo(h.ctx)

	return nil
}

// GetAttribute retrieves the value of specified element attribute.
// The second return value is true if the attribute exists, and false otherwise.
func (h *ElementHandle) GetAttribute(name string) (string, bool, error) {
	getAttribute := func(apiCtx context.Context, handle *ElementHandle) (any, error) {
		return handle.getAttribute(apiCtx, name)
	}
	opts := NewElementHandleBaseOptions(h.DefaultTimeout())
	getAttributeAction := h.newAction(
		[]string{}, getAttribute, opts.Force, withRetry, opts.NoWaitAfter, opts.Timeout,
	)

	v, err := call(h.ctx, getAttributeAction, opts.Timeout)
	if err != nil {
		return "", false, fmt.Errorf("getting attribute %q of element: %w", name, err)
	}
	if v == nil {
		return "", false, nil
	}
	s, ok := v.(string)
	if !ok {
		return "", false, fmt.Errorf(
			"getting attribute %q of element: unexpected type %T (expecting string)",
			name, v,
		)
	}

	return s, true, nil
}

// Hover scrolls element into view and hovers over its center point.
func (h *ElementHandle) Hover(opts *ElementHandleHoverOptions) error {
	hover := func(apiCtx context.Context, handle *ElementHandle, p *Position) (any, error) {

View on GitHub (pinned to 93accf6570)

Solutions

  1. Re-query the handle right before getAttribute instead of reusing an earlier page.$() result
  2. Wait for the element: page.waitForSelector(sel, { state: 'attached' })
  3. Call it after page.waitForLoadState() when a navigation just happened
  4. Increase the action timeout if the underlying error is a timeout

Example fix

// before
const h = await page.$('a.link');
const [href, ok] = await h.getAttribute('href');
// after
await page.waitForSelector('a.link', { state: 'attached' });
const h = await page.$('a.link');
const [href, ok] = await h.getAttribute('href');
Defensive patterns

Strategy: try-catch

Validate before calling

await page.waitForSelector('a.link', { state: 'attached' });
const h = await page.$('a.link');
const [href, ok] = await h.getAttribute('href');
if (!ok) { /* attribute absent: not an error */ }

Try / catch

try {
  const [v, ok] = await handle.getAttribute(name);
} catch (e) {
  if (String(e).includes('getting attribute')) {
    await page.waitForLoadState();
    return (await page.$(sel)).getAttribute(name);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling getAttribute on a handle whose node was detached (SPA re-render) or that predates a navigation; calling it while the page is navigating (execution context destroyed); timeout expired while the action retried; browser/page closed mid-call.

Common situations: Reading data-* attributes from dynamically re-rendered lists where handles go stale; mixing goto() and old handles in the same iteration; CI runs where the browser is slow and default timeouts are tight.

Related errors


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