{"record":{"id":"34354da6793a11c8","repo":"grafana/k6","slug":"getting-frame-title-w","errorCode":null,"errorMessage":"getting frame title: %w","messagePattern":"getting frame title: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/common/frame.go","lineNumber":1890,"sourceCode":"\t}\n\n\treturn s, true, nil\n}\n\n// Timeout will return the default timeout or the one set by the user.\n// It's an internal method not to be exposed as a JS API.\nfunc (f *Frame) Timeout() time.Duration {\n\treturn f.defaultTimeout()\n}\n\n// Title returns the title of the frame.\nfunc (f *Frame) Title() (string, error) {\n\tf.log.Debugf(\"Frame:Title\", \"fid:%s furl:%q\", f.ID(), f.URL())\n\n\tjs := `() => document.title`\n\tv, err := f.Evaluate(js)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"getting frame title: %w\", err)\n\t}\n\ts, ok := v.(string)\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"getting frame title: expected string, got %T\", v)\n\t}\n\n\treturn s, nil\n}\n\n// Type text on the first element found matches the selector.\nfunc (f *Frame) Type(selector, text string, popts *FrameTypeOptions) error {\n\tf.log.Debugf(\"Frame:Type\", \"fid:%s furl:%q sel:%q text:%q\", f.ID(), f.URL(), selector, text)\n\n\tif err := f.typ(selector, text, popts); err != nil {\n\t\treturn fmt.Errorf(\"typing %q in %q: %w\", text, selector, err)\n\t}\n\n\tapplySlowMo(f.ctx)","sourceCodeStart":1872,"sourceCodeEnd":1908,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/browser/common/frame.go#L1872-L1908","documentation":"Frame.Title() evaluates `() => document.title` in the frame; an evaluation failure is wrapped as 'getting frame title: <cause>'. The cause is a frame/execution-context problem — navigating, detached, closed, or the k6 context cancelled — since document.title itself cannot throw.","triggerScenarios":"frame.title() during navigation before the new context is ready; on a detached iframe; after page.close(); when the iteration's context is cancelled by k6 timeouts.","commonSituations":"Calling title() immediately after goto() while redirects settle; harvesting titles for every frame in page.frames() when some iframes are ad placeholders that detach constantly.","solutions":["Wait for load state before reading the title: await page.waitForLoadState('load').","Skip frames that are detached or about:blank/sandboxed ad frames when iterating page.frames().","Retry once — titles are read-many times and transient context gaps resolve quickly."],"exampleFix":"// before\nfor (const f of page.frames()) console.log(await f.title()); // ad frames detach\n\n// after\nfor (const f of page.frames()) {\n  if (f !== page.mainFrame() && f.url() === 'about:blank') continue;\n  console.log(await f.title().catch(() => '<no title>'));\n}","handlingStrategy":"try-catch","validationCode":"if (page.isClosed()) throw new Error('page closed');\nawait page.waitForLoadState('load');","typeGuard":null,"tryCatchPattern":"try { return await frame.title(); }\ncatch (e) { if (/getting frame title/.test(e.message)) { return ''; } throw e; }","preventionTips":["Wait for load state before reading titles","Skip detached/blank iframes when iterating frames","Default titles to empty string on failure rather than failing the iteration"],"tags":["browser","frame","navigation","execution-context"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}