grafana/k6 · error
getting frame title: expected string, got %T
Error message
getting frame title: expected string, got %T
What it means
Frame.Title() got a successful evaluation result that is not a Go string, so the assertion `v.(string)` fails: 'getting frame title: expected string, got <T>'. document.title is always a string in a healthy page, so a non-string result means the evaluation resolved against a replaced/destroyed context or a protocol-level anomaly.
Source
Thrown at internal/js/modules/k6/browser/common/frame.go:1894
// Timeout will return the default timeout or the one set by the user.
// It's an internal method not to be exposed as a JS API.
func (f *Frame) Timeout() time.Duration {
return f.defaultTimeout()
}
// Title returns the title of the frame.
func (f *Frame) Title() (string, error) {
f.log.Debugf("Frame:Title", "fid:%s furl:%q", f.ID(), f.URL())
js := `() => document.title`
v, err := f.Evaluate(js)
if err != nil {
return "", fmt.Errorf("getting frame title: %w", err)
}
s, ok := v.(string)
if !ok {
return "", fmt.Errorf("getting frame title: expected string, got %T", v)
}
return s, nil
}
// Type text on the first element found matches the selector.
func (f *Frame) Type(selector, text string, popts *FrameTypeOptions) error {
f.log.Debugf("Frame:Type", "fid:%s furl:%q sel:%q text:%q", f.ID(), f.URL(), selector, text)
if err := f.typ(selector, text, popts); err != nil {
return fmt.Errorf("typing %q in %q: %w", text, selector, err)
}
applySlowMo(f.ctx)
return nil
}
View on GitHub (pinned to 93accf6570)
Solutions
- Wait for the frame to settle (waitForLoadState) and call title() again — the result is transient.
- Read defensively: const t = await frame.evaluate(() => document.title).catch(() => '');
- Update k6 so the module and bundled chromium match.
Example fix
// before
const t = await frame.title(); // intermittent type error
// after
await frame.waitForLoadState('load');
const t = await frame.title().catch(() => ''); Defensive patterns
Strategy: try-catch
Validate before calling
await frame.waitForLoadState('load'); Type guard
const isStr = (v) => typeof v === 'string';
Try / catch
try { return await frame.title(); }
catch (e) {
if (/expected string/.test(e.message)) {
return frame.evaluate(() => document.title).catch(() => '');
}
throw e;
} Prevention
- Read titles after navigation settles
- Use evaluate as the fallback read path
- Update k6/chromium pairs together
When it happens
Trigger: Navigation replaced the execution context between evaluate dispatch and result deserialization; the frame was detached mid-call; version skew between k6's browser module and the chromium binary.
Common situations: Intermittent, seen on pages that navigate frequently (redirects, meta refresh); almost never reproducible twice in a row on a static page.
Related errors
- getting new document handle: %w
- document element handle is nil
- missing required argument 'url'
- getting document element: nil document
- waitFor retry threshold reached
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/f7c9dc44e077d5e6.
Report an issue: GitHub.