{"record":{"id":"a9f221415a5e02b8","repo":"microg/GmsCore","slug":"invalid-handle-a9f221","errorCode":null,"errorMessage":"invalid handle","messagePattern":"invalid handle","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"play-services-recaptcha/core/src/main/kotlin/org/microg/gms/recaptcha/RecaptchaWebImpl.kt","lineNumber":151,"sourceCode":"        val request = RecaptchaExecuteRequest(token = lastRequestToken, action = params.action.toString(), additionalArgs = additionalArgs).encode().toBase64(Base64.URL_SAFE, Base64.NO_WRAP)\n        val token = suspendCoroutine { continuation ->\n            executeFinished.set(false)\n            executeContinuation = continuation\n            eval(\"recaptcha.m.Main.execute(\\\"${request}\\\")\")\n            lifecycleScope.launch {\n                delay(10000)\n                if (!executeFinished.getAndSet(true)) {\n                    try {\n                        continuation.resumeWithException(RuntimeException(\"Timeout reached\"))\n                    } catch (_: Exception) {}\n                }\n            }\n        }\n        return RecaptchaResultData(token)\n    }\n\n    override suspend fun close(handle: RecaptchaHandle): Boolean {\n        if (handle.clientPackageName != null && handle.clientPackageName != packageName) throw IllegalArgumentException(\"invalid handle\")\n        val closed = webView != null\n        webView?.stopLoading()\n        webView?.loadUrl(\"about:blank\")\n        webView = null\n        return closed\n    }\n\n    private fun eval(script: String) {\n        Log.d(TAG, \"eval: $script\")\n        webView?.let {\n            Handler(context.mainLooper).post {\n                it.evaluateJavascript(script, null)\n            }\n        }\n    }\n\n    protected fun finalize() {\n        FakeApplication.packageNameOverride = \"\"","sourceCodeStart":133,"sourceCodeEnd":169,"githubUrl":"https://github.com/microg/GmsCore/blob/157c9d86ac46c195a86c2f15ab55c84036223f95/play-services-recaptcha/core/src/main/kotlin/org/microg/gms/recaptcha/RecaptchaWebImpl.kt#L133-L169","documentation":"RecaptchaWebImpl.close() enforces handle ownership: if handle.clientPackageName is non-null and differs from the packageName this web-based reCAPTCHA implementation serves, it throws IllegalArgumentException(\"invalid handle\"). It prevents closing a WebView-based reCAPTCHA session belonging to a different app.","triggerScenarios":"Calling close(handle) with a handle whose clientPackageName points at another package — cross-app handle reuse, restored/stale handles, or wrong package in test-constructed handles.","commonSituations":"Web-view reCAPTCHA handles shared across activities running under different package identities, handles persisted and reused after the app was renamed, or instrumentation tests passing mismatched package names.","solutions":["Use only handles returned by init() from the same RecaptchaWebImpl instance","Null out or correctly set clientPackageName when constructing handles in tests","Re-init to obtain a fresh valid handle instead of reusing persisted ones","Verify the app's packageName matches what was passed when the service was created"],"exampleFix":"// before\nwebImpl.close(handle) // handle.clientPackageName = \"com.other\"\n// after\ncheck(handle.clientPackageName == null || handle.clientPackageName == packageName)\nwebImpl.close(handle)","handlingStrategy":"validation","validationCode":"require(handle.clientPackageName == null || handle.clientPackageName == packageName)","typeGuard":"fun RecaptchaHandle.belongsTo(pkg: String) = clientPackageName == null || clientPackageName == pkg","tryCatchPattern":"try { webImpl.close(handle) } catch (e: IllegalArgumentException) { webImpl.close(webImpl.init(params)) }","preventionTips":["Keep handle and impl instance paired","Avoid persisting web handles across sessions","Correct clientPackageName in tests"],"tags":["kotlin","recaptcha","webview","argument-validation"],"backgroundTag":"invalid-argument-value","analyzedSha":"157c9d86ac46c195a86c2f15ab55c84036223f95","analyzedAt":"2026-09-06T17:27:33.892Z","contentChangedAt":"2026-09-06T17:27:33.892Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}