grafana/k6 · error · TypeError
${name} constructor must be called with new
Error message
${name} constructor must be called with new What it means
After the isEditable action succeeds (frame.go:1438), k6 asserts the returned value is a bool; otherwise it returns 'checking is %q editable: unexpected type %T'. The underlying waitForElementState call returns a Go bool, so a non-bool (typically nil) means the action machinery produced an unexpected value: usually a race where the frame/context died between resolution and result, or a k6 browser-module bug in value plumbing. It is an internal invariant break, not a normal test failure.
Source
Thrown at internal/js/modules/k6/experimental/streams/sobek.go:22
"fmt"
"reflect"
"slices"
"github.com/grafana/sobek"
"go.k6.io/k6/v2/js/common"
"go.k6.io/k6/v2/js/modules"
)
// newWebIDLConstructor wraps a native Sobek constructor so it follows Web IDL call semantics.
// Sobek otherwise treats a native constructor call without `new` exactly like construction and
// does not expose a NewTarget that lets the native function distinguish the two cases.
func newWebIDLConstructor(rt *sobek.Runtime, name string, constructor any) (sobek.Value, error) {
factory, err := rt.RunString(`
(function(constructor, name) {
const wrapper = function(...args) {
if (new.target === undefined) {
throw new TypeError(name + " constructor must be called with new");
}
return Reflect.construct(constructor, args, new.target);
};
Object.defineProperty(wrapper, "name", { value: name, configurable: true });
return wrapper;
})`)
if err != nil {
return nil, err
}
call, ok := sobek.AssertFunction(factory)
if !ok {
return nil, newError(RuntimeError, "Web IDL constructor wrapper factory is not a function")
}
return call(sobek.Undefined(), rt.ToValue(constructor), rt.ToValue(name))
}
View on GitHub (pinned to 01ffac6f24)
Solutions
- Retry the check once after waiting for a stable state (waitForLoadState or locator.waitFor) — most instances are transient races.
- Make sure the frame is not being navigated while the check runs.
- Reproduce with K6_DEBUG=true to capture the wrapped context.
- If reproducible, open a grafana/k6 issue with the script, page, and k6 version.
Example fix
// before
const ok = await page.isEditable('#comment');
// after
async function isEditableStable(sel) {
for (let i = 0; i < 3; i++) {
try { return await page.isEditable(sel); }
catch (e) { if (!String(e).includes('unexpected type')) throw e; }
}
throw new Error('isEditable unstable: ' + sel);
}
const ok = await isEditableStable('#comment'); Defensive patterns
Strategy: retry
Validate before calling
await page.waitForLoadState('domcontentloaded'); // avoid checking while navigation is in flight Try / catch
try {
return await page.isEditable(sel);
} catch (e) {
if (!String(e).includes('unexpected type')) throw e;
await page.waitForLoadState('domcontentloaded');
return await page.isEditable(sel); // transient race; retry once
} Prevention
- Don't run state checks concurrently with navigation or iframe swaps.
- Stabilize the page (waitForLoadState/locator.waitFor) before asserting state.
- Capture K6_DEBUG logs when it flakes to identify the racing event.
When it happens
Trigger: Frame detaches or navigates between selector resolution and the state result; the action returns a nil result on a rare error path; DevTools protocol/session teardown races during the check; k6 browser-module regression.
Common situations: Flaky failures in CI on slow machines during page transitions; races in SPA tests where checks run exactly as iframes swap; after a k6 version upgrade introducing a conversion bug.
Related errors
- failed to authenticate with k6 Cloud
- an error occurred communicating with the provisioning API
- Error while parsing selector `${selector}` - selector cannot
- "level" attribute must be compared to a number
- "name" attribute must be a string or a regular expression
AI-assisted analysis of grafana/k6@01ffac6f24 (2026-08-18).
Data as JSON: /api/errors/d219e0d0cd370fcb.
Report an issue: GitHub.