CloakHQ/CloakBrowser · error · StealthEvaluationError

<scroll-state>

Error message

<scroll-state>

What it means

StealthEvaluationError thrown by GetScrollStateAsync when evaluating the scroll-state JS (window.scrollY and scrollingElement maxHeight) fails to return a well-formed {y, maxY} object in the isolated world.

Source

Thrown at dotnet/src/CloakBrowser/Human/PlaywrightAdapters.cs:121

        int resolvedWidth = (int)width.GetDouble();
        int resolvedHeight = (int)height.GetDouble();
        if (resolvedWidth <= 0 || resolvedHeight <= 0)
            throw new StealthEvaluationError("<viewport>");
        return (resolvedWidth, resolvedHeight);
    }

    public async Task<(double Y, double MaxY)?> GetScrollStateAsync()
    {
        var world = await _getStealthAsync().ConfigureAwait(false);
        var value = await world.EvaluateAsync(
            "(() => { const e = document.scrollingElement || document.documentElement;" +
            " return { y: window.scrollY, maxY: Math.max(0, e.scrollHeight - e.clientHeight) }; })()")
            .ConfigureAwait(false);
        if (value == null || value.Value.ValueKind != System.Text.Json.JsonValueKind.Object
            || !value.Value.TryGetProperty("y", out var y)
            || !value.Value.TryGetProperty("maxY", out var maxY))
            throw new StealthEvaluationError("<scroll-state>");
        return (y.GetDouble(), maxY.GetDouble());
    }
}

View on GitHub (pinned to d6bad5de26)

Solutions

  1. Wait for a settled load state before scroll APIs
  2. Verify the page is open (IsClosed == false) before calling
  3. Use CloakBrowser's own context/page creation path so the isolated world exists
  4. Wrap in a retry for transient navigation races

Example fix

// before
await page.HumanScrollByAsync(300);

// after
await page.WaitForLoadStateAsync(LoadState.DOMContentLoaded);
if (!page.IsClosed) await page.HumanScrollByAsync(300);
Defensive patterns

Strategy: retry

Validate before calling

await page.WaitForLoadStateAsync(LoadState.DOMContentLoaded);
if (page.IsClosed) return;

Try / catch

catch (StealthEvaluationError e) when (e.Message == "<scroll-state>") { settle, then retry once }

Prevention

When it happens

Trigger: Calling scroll-state-dependent humanize APIs when the stealth world EvaluateAsync returns null or a non-object — typically because the page is navigating, crashed, closed, or the stealth scripts/world aren't installed.

Common situations: Races with navigation, humanize calls after page.CloseAsync, or custom context construction that skips CloakBrowser's stealth injection.

Related errors


AI-assisted analysis of CloakHQ/CloakBrowser@d6bad5de26 (2026-08-28). Data as JSON: /api/errors/1055cdcd22e7dcc6. Report an issue: GitHub.