{"record":{"id":"22d1a98dc6b9fb9c","repo":"grafana/k6","slug":"document-element-handle-is-nil","errorCode":null,"errorMessage":"document element handle is nil","messagePattern":"document element handle is nil","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/common/frame.go","lineNumber":292,"sourceCode":"\n\treturn f.documentHandle, f.documentHandle != nil\n}\n\nfunc (f *Frame) newDocumentHandle() (*ElementHandle, error) {\n\tresult, err := f.evaluate(\n\t\tf.ctx,\n\t\tmainWorld,\n\t\tevalOptions{\n\t\t\tforceCallable: false,\n\t\t\treturnByValue: false,\n\t\t},\n\t\t\"document\",\n\t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"getting document element handle: %w\", err)\n\t}\n\tif result == nil {\n\t\treturn nil, fmt.Errorf(\"document element handle is nil\")\n\t}\n\tdh, ok := result.(*ElementHandle)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"unexpected document handle type: %T\", result)\n\t}\n\n\treturn dh, nil\n}\n\nfunc (f *Frame) hasContext(world executionWorld) bool {\n\tf.executionContextMu.RLock()\n\tdefer f.executionContextMu.RUnlock()\n\n\treturn f.executionContexts[world] != nil\n}\n\nfunc (f *Frame) hasLifecycleEventFired(event LifecycleEvent) bool {\n\tf.lifecycleEventsMu.RLock()","sourceCodeStart":274,"sourceCodeEnd":310,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/browser/common/frame.go#L274-L310","documentation":"The evaluate of 'document' returned no error but also no result: the remote object came back nil (the code logs 'remoteObject is nil' at Debug level in ExecutionContext.eval). That happens while a context is being torn down — Chrome accepts the evaluation but the object never materializes. It is a nil-check guard in newDocumentHandle signaling the same navigation/teardown race as its siblings, not a script error.","triggerScenarios":"Evaluating 'document' exactly as the context is destroyed by navigation; frame detach between context acquisition and evaluation; page closing mid-query.","commonSituations":"Fast SPA transitions; queries fired at the tail end of an iteration while the browser cleans up; flaky timing on CI machines.","solutions":["Retry the query after waiting for load state","Synchronize navigations with waitForNavigation before querying","Avoid querying during page teardown; sequence actions before close()"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  el = await page.waitForSelector('#x');\n} catch (e) {\n  if (/document element handle is nil/.test(e.message)) {\n    await page.waitForLoadState();\n    el = await page.waitForSelector('#x');\n  } else throw e;\n}","preventionTips":["Synchronize navigations with waitForNavigation before querying","Sequence all actions before page.close() to avoid teardown races","Retry once on teardown-race flakes before declaring failure"],"tags":["browser","frame","race-condition","navigation"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}