{"record":{"id":"46f93cb07b9b18e6","repo":"CloakHQ/CloakBrowser","slug":"stealthworldunavailableerror-46f93c","errorCode":null,"errorMessage":"StealthWorldUnavailableError","messagePattern":"StealthWorldUnavailableError","errorType":"exception","errorClass":"StealthWorldUnavailableError","httpStatus":null,"severity":"error","filePath":"dotnet/src/CloakBrowser/Human/Actionability.cs","lineNumber":145,"sourceCode":"\n    /// <summary>\n    /// Wait for the element to pass actionability checks (pre-scroll). Retries\n    /// with backoff until <paramref name=\"timeoutMs\"/> elapsed. Throws a specific\n    /// <see cref=\"ActionabilityError\"/> subclass on failure. Returns immediately\n    /// when <paramref name=\"force\"/> is true.\n    /// </summary>\n    public static async Task EnsureActionableAsync(\n        IPage page,\n        string selector,\n        IReadOnlySet<string> checks,\n        double timeoutMs = 30000,\n        bool force = false,\n        IsolatedWorld? stealth = null)\n    {\n        if (force)\n            return;\n        if (stealth == null)\n            throw new StealthWorldUnavailableError();\n\n        double deadline = NowMs() + timeoutMs;\n        int attempt = 0;\n        Exception? lastError = null;\n\n        while (true)\n        {\n            double remainingMs = Math.Max(0, deadline - NowMs());\n            if (remainingMs <= 0)\n            {\n                if (lastError != null)\n                    throw lastError;\n                throw new ActionabilityError(selector, \"timeout\", \"timeout expired before first check\");\n            }\n\n            try\n            {\n                var (status, snapshot) = await StealthDom.ActionableAsync(","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/CloakHQ/CloakBrowser/blob/d6bad5de261bedf025280ace1d14e800aee13923/dotnet/src/CloakBrowser/Human/Actionability.cs#L127-L163","documentation":"EnsureActionableAsync requires an IsolatedWorld handle to run its DOM checks in the browser's isolated world; passing a null stealth world (and not force-skipping) is a programming error. The library throws this dedicated error type so callers distinguish 'misuse' from DOM-level failures. It never happens when force: true is set.","triggerScenarios":"Calling EnsureActionableAsync/EnsureActionableWorldAsync with stealth: null and force: false — typically when a humanized session was not created, the isolated world was torn down, or a caller forgot to obtain the world handle before humanizing an element.","commonSituations":"Calling humanize APIs before attaching the stealth isolated world; reusing a session after browser navigation or disposal dropped the world; refactoring that lost the stealth parameter; race where the world is closed mid-flow.","solutions":["Pass the IsolatedWorld obtained from the stealth session setup before calling EnsureActionableAsync.","If you intentionally want to skip the checks, pass force: true instead of null stealth.","Re-acquire the isolated world after navigation/disposal events that invalidate it.","Guard call sites with a null-check that either re-initializes the world or skips humanization."],"exampleFix":"// before\nawait Actionability.EnsureActionableAsync(page, selector, stealth: null); // throws\n\n// after\nif (stealth is null)\n    stealth = await page.AcquireIsolatedWorldAsync();\nawait Actionability.EnsureActionableAsync(page, selector, stealth: stealth);\n// or intentionally skip: await Actionability.EnsureActionableAsync(page, selector, force: true);","handlingStrategy":"type-guard","validationCode":"if (stealth is null && !force)\n    stealth = await page.AcquireIsolatedWorldAsync();\nawait Actionability.EnsureActionableAsync(page, selector, stealth, force: force);","typeGuard":"static bool HasStealthWorld(IsolatedWorld? w) => w is { IsClosed: false };","tryCatchPattern":"catch (StealthWorldUnavailableError)\n{\n    stealth = await page.AcquireIsolatedWorldAsync(); // re-acquire and retry once\n    await Actionability.EnsureActionableAsync(page, selector, stealth);\n}","preventionTips":["Always acquire the isolated world during session setup and store it alongside the page.","Pass force: true when you explicitly want to bypass checks rather than null stealth.","Re-acquire the world after navigation, reload, or frame swap events."],"tags":["stealth","isolated-world","misuse","api-contract"],"backgroundTag":"null-required-argument","analyzedSha":"d6bad5de261bedf025280ace1d14e800aee13923","analyzedAt":"2026-08-28T14:13:12.918Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}