{"record":{"id":"501cd4199183f6e1","repo":"grafana/k6","slug":"disposing-element-handle-w","errorCode":null,"errorMessage":"disposing element handle: %w","messagePattern":"disposing element handle: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/js/modules/k6/browser/common/element_handle.go","lineNumber":1239,"sourceCode":"\t\tforceCallable: true,\n\t\treturnByValue: false,\n\t}\n\tresult, err := h.evalWithScript(h.ctx, opts, querySelector, parsedSelector, strict)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"querying selector %q: %w\", selector, err)\n\t}\n\tif result == nil {\n\t\treturn nil, nil //nolint:nilnil\n\t}\n\thandle, ok := result.(JSHandleAPI)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"querying selector %q, wrong type %T\", selector, result)\n\t}\n\telement := handle.AsElement()\n\tif element == nil {\n\t\tdefer func() {\n\t\t\tif err := handle.Dispose(); err != nil {\n\t\t\t\terr = fmt.Errorf(\"disposing element handle: %w\", err)\n\t\t\t\trerr = errors.Join(err, rerr)\n\t\t\t}\n\t\t}()\n\t\treturn nil, fmt.Errorf(\"querying selector %q\", selector)\n\t}\n\n\treturn element, nil\n}\n\n// QueryAll queries element subtree for matching elements.\n// If no element matches the selector, the return value resolves to \"null\".\nfunc (h *ElementHandle) QueryAll(selector string) ([]*ElementHandle, error) {\n\thandles, err := h.queryAll(selector, h.evalWithScript)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"querying all selector %q: %w\", selector, err)\n\t}\n\n\treturn handles, nil","sourceCodeStart":1221,"sourceCodeEnd":1257,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/browser/common/element_handle.go#L1221-L1257","documentation":"In ElementHandle.Query(), when the queried handle turns out not to be an element, a deferred Dispose() of that useless handle failed and its error is joined onto the return error (element_handle.go:1239). The dispose failure itself is secondary — the primary problem is the accompanying 'querying selector' error; dispose fails when the session/target is already gone.","triggerScenarios":"The result handle is a non-element node AND the browser target, page, or execution context was destroyed before the cleanup Dispose ran (navigation or close during the call).","commonSituations":"End-of-iteration cleanup races: k6 closes the browser while a query is finishing; the joined error adds noise on top of the real failure.","solutions":["Fix the primary error first (see 'querying selector ...') — this error only rides along","Make sure no navigation/close happens while browser promises are pending","If the target is already closed, this error can be safely ignored in logs","Upgrade k6; dispose-after-close handling has been improved over releases"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { const child = await el.$(sel); }\ncatch (e) { /* primary 'querying selector' error is the actionable one; ignore joined dispose error if target closed */ if (!/disposing element handle/.test(e.message)) throw e; }","preventionTips":["Diagnose the primary error, not the joined dispose noise","Keep the browser open until all pending ops settle"],"tags":["browser","cleanup","disposal","race-condition"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}