CloakHQ/CloakBrowser · error · StealthWorldUnavailableError
StealthWorldUnavailableError
Error message
StealthWorldUnavailableError
What it means
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.
Source
Thrown at dotnet/src/CloakBrowser/Human/Actionability.cs:145
/// <summary>
/// Wait for the element to pass actionability checks (pre-scroll). Retries
/// with backoff until <paramref name="timeoutMs"/> elapsed. Throws a specific
/// <see cref="ActionabilityError"/> subclass on failure. Returns immediately
/// when <paramref name="force"/> is true.
/// </summary>
public static async Task EnsureActionableAsync(
IPage page,
string selector,
IReadOnlySet<string> checks,
double timeoutMs = 30000,
bool force = false,
IsolatedWorld? stealth = null)
{
if (force)
return;
if (stealth == null)
throw new StealthWorldUnavailableError();
double deadline = NowMs() + timeoutMs;
int attempt = 0;
Exception? lastError = null;
while (true)
{
double remainingMs = Math.Max(0, deadline - NowMs());
if (remainingMs <= 0)
{
if (lastError != null)
throw lastError;
throw new ActionabilityError(selector, "timeout", "timeout expired before first check");
}
try
{
var (status, snapshot) = await StealthDom.ActionableAsync(View on GitHub (pinned to d6bad5de26)
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.
Example fix
// before
await Actionability.EnsureActionableAsync(page, selector, stealth: null); // throws
// after
if (stealth is null)
stealth = await page.AcquireIsolatedWorldAsync();
await Actionability.EnsureActionableAsync(page, selector, stealth: stealth);
// or intentionally skip: await Actionability.EnsureActionableAsync(page, selector, force: true); Defensive patterns
Strategy: type-guard
Validate before calling
if (stealth is null && !force)
stealth = await page.AcquireIsolatedWorldAsync();
await Actionability.EnsureActionableAsync(page, selector, stealth, force: force); Type guard
static bool HasStealthWorld(IsolatedWorld? w) => w is { IsClosed: false }; Try / catch
catch (StealthWorldUnavailableError)
{
stealth = await page.AcquireIsolatedWorldAsync(); // re-acquire and retry once
await Actionability.EnsureActionableAsync(page, selector, stealth);
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Invalid browser version pin. Use a full numeric Chromium ver
- Unsupported platform: ${platform} ${arch}. Supported: ${supp
- CloakBrowser Pro: license could not be validated (server unr
- Download completed but binary not found at expected path: ${
- Pro download completed but binary not found at: ${getBinaryP
AI-assisted analysis of CloakHQ/CloakBrowser@d6bad5de26 (2026-08-28).
Data as JSON: /api/errors/46f93cb07b9b18e6.
Report an issue: GitHub.