{"record":{"id":"3697332caa1459c9","repo":"grafana/k6","slug":"getting-frame-content-expected-string-got-t","errorCode":null,"errorMessage":"getting frame content: expected string, got %T","messagePattern":"getting frame content: expected string, got %T","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/common/frame.go","lineNumber":786,"sourceCode":"\n\tjs := `() => {\n\t\tlet content = '';\n\t\tif (document.doctype) {\n\t\t\tcontent = new XMLSerializer().serializeToString(document.doctype);\n\t\t}\n\t\tif (document.documentElement) {\n\t\t\tcontent += document.documentElement.outerHTML;\n\t\t}\n\t\treturn content;\n\t}`\n\n\tv, err := f.Evaluate(js)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"getting frame content: %w\", err)\n\t}\n\ts, ok := v.(string)\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"getting frame content: expected string, got %T\", v)\n\t}\n\n\treturn s, nil\n}\n\n// Dblclick double clicks an element matching provided selector.\nfunc (f *Frame) Dblclick(selector string, popts *FrameDblclickOptions) error {\n\tf.log.Debugf(\"Frame:DblClick\", \"fid:%s furl:%q sel:%q\", f.ID(), f.URL(), selector)\n\n\tif err := f.dblclick(selector, popts); err != nil {\n\t\treturn fmt.Errorf(\"double clicking on %q: %w\", selector, err)\n\t}\n\n\tapplySlowMo(f.ctx)\n\n\treturn nil\n}\n","sourceCodeStart":768,"sourceCodeEnd":804,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/browser/common/frame.go#L768-L804","documentation":"Frame.Content() evaluates with returnByValue and expects a Go string back. If evaluation succeeded but the returned value is not a string (nil remote object, unexpected CDP type), this assertion fails. It is an internal contract violation between the serializer script and the evaluate pipeline rather than a user-input error.","triggerScenarios":"The page's document has no documentElement at serialization time (about:blank race, document being replaced mid-call); a module regression changing what Evaluate returns for returnByValue calls.","commonSituations":"Calling content() extremely early after page creation or during document replacement; k6 version upgrade introducing an evaluate regression.","solutions":["Wait for a real document: waitForLoadState('domcontentloaded') before content().","Retry the call once after the page settles.","If reproducible on a stable loaded page, report as a k6 browser module bug."],"exampleFix":"// before\nconst html = page.content(); // called during document swap\n\n// after\nawait page.waitForLoadState('domcontentloaded');\nconst html = page.content();","handlingStrategy":"try-catch","validationCode":"await page.waitForLoadState('domcontentloaded');","typeGuard":"const isHtmlString = (s) => typeof s === 'string' && s.length > 0;","tryCatchPattern":"let html;\ntry {\n  html = page.content();\n} catch (e) {\n  console.warn('content() returned non-string, retrying after load');\n  await page.waitForLoadState('load');\n  html = page.content();\n}\nif (!isHtmlString(html)) throw new Error('content still invalid');","preventionTips":["Wait for domcontentloaded before serializing the DOM.","Avoid content() during document replacement (redirects).","Pin known-good k6 versions; report invariant failures upstream."],"tags":["browser","content","type-assertion","internal-invariant","load-state"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}