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
- Wait for a settled load state before scroll APIs
- Verify the page is open (IsClosed == false) before calling
- Use CloakBrowser's own context/page creation path so the isolated world exists
- 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
- Wait for load state before scroll APIs
- Avoid scroll calls during teardown
- Keep stealth scripts installed
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
- <viewport>
- StealthEvaluationError: {selector}
- Invalid browser version pin. Use a full numeric Chromium ver
- CloakBrowser — Pre-built binaries are currently only availab
- CloakBrowser Pro: license key is invalid or expired (plan=${
AI-assisted analysis of CloakHQ/CloakBrowser@d6bad5de26 (2026-08-28).
Data as JSON: /api/errors/1055cdcd22e7dcc6.
Report an issue: GitHub.