grafana/k6 · error
getting properties for element with ID %s: %w
Error message
getting properties for element with ID %s: %w
What it means
Thrown by BaseJSHandle.getProperties when the CDP Runtime.getProperties call fails for the handle's remote object ID. The remote object referenced by the handle no longer exists in the browser (it was disposed, garbage-collected, or its context was destroyed), so the DevTools protocol cannot enumerate its properties.
Source
Thrown at internal/js/modules/k6/browser/common/js_handle.go:177
handles, err := h.getProperties()
if err != nil {
return nil, err
}
jsHandles := make(map[string]JSHandleAPI, len(handles))
for k, v := range handles {
jsHandles[k] = v
}
return jsHandles, nil
}
// getProperties is like GetProperties, but does not panic.
func (h *BaseJSHandle) getProperties() (map[string]jsHandle, error) {
act := runtime.GetProperties(h.remoteObject.ObjectID).WithOwnProperties(true)
result, _, _, _, err := act.Do(cdp.WithExecutor(h.ctx, h.session)) //nolint:dogsled
if err != nil {
return nil, fmt.Errorf("getting properties for element with ID %s: %w",
h.remoteObject.ObjectID, err)
}
props := make(map[string]jsHandle, len(result))
for _, r := range result {
if !r.Enumerable {
continue
}
props[r.Name] = NewJSHandle(h.ctx, h.session, h.execCtx, h.execCtx.Frame(), r.Value, h.logger)
}
return props, nil
}
// JSONValue returns a JSON version of this JS handle.
func (h *BaseJSHandle) JSONValue() (string, error) {
remoteObject := h.remoteObject
if remoteObject.ObjectID != "" {View on GitHub (pinned to 93accf6570)
Solutions
- Never use a handle after calling dispose() on it; drop all references or re-query the element
- Re-acquire the handle (page.$ / locator) immediately before GetProperties when navigation may have occurred
- Check that the page and browser context are still open before calling
- Wrap in try/catch and re-query the element once on failure
Example fix
// before
const h = await page.$('.cfg');
await h.dispose();
const props = await h.getProperties(); // object already released
// after
let h = await page.$('.cfg');
let props;
try {
props = await h.getProperties();
} catch (e) {
h = await page.$('.cfg'); // stale handle, re-acquire
props = await h.getProperties();
} Defensive patterns
Strategy: try-catch
Validate before calling
if (page.isClosed()) throw new Error('page closed'); // disposed handles cannot be validated from JS — do not call dispose() before GetProperties Try / catch
try {
const props = await handle.getProperties();
} catch (e) {
if (/getting properties for element/.test(e.message)) {
const fresh = await page.$(selector);
return fresh.getProperties(); // object ID was released/GC'd: re-acquire
}
throw e;
} Prevention
- Never reuse a handle after dispose()
- Query handles fresh in each iteration instead of caching
- Avoid long gaps between element.$() and getProperties()
When it happens
Trigger: Calling GetProperties() after handle.dispose() released the object; holding a handle across a navigation that destroyed its execution context; the browser garbage-collecting the JS object while the handle still references its ObjectID; the CDP session being closed mid-call.
Common situations: Caching handles globally in a long test instead of re-querying per iteration; disposing a handle then reusing it; page closing (browser.close or context.close) before the call completes.
Related errors
- retrieving json value: %w
- disposing element with ID %s: %w
- evaluating element: %w
- evaluating handle for element: %w
- WebSocket endpoint cannot be empty
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/73b0602d8dfc6912.
Report an issue: GitHub.