{"record":{"id":"1055cdcd22e7dcc6","repo":"CloakHQ/CloakBrowser","slug":"scroll-state","errorCode":null,"errorMessage":"<scroll-state>","messagePattern":"<scroll-state>","errorType":"exception","errorClass":"StealthEvaluationError","httpStatus":null,"severity":"error","filePath":"dotnet/src/CloakBrowser/Human/PlaywrightAdapters.cs","lineNumber":121,"sourceCode":"\n        int resolvedWidth = (int)width.GetDouble();\n        int resolvedHeight = (int)height.GetDouble();\n        if (resolvedWidth <= 0 || resolvedHeight <= 0)\n            throw new StealthEvaluationError(\"<viewport>\");\n        return (resolvedWidth, resolvedHeight);\n    }\n\n    public async Task<(double Y, double MaxY)?> GetScrollStateAsync()\n    {\n        var world = await _getStealthAsync().ConfigureAwait(false);\n        var value = await world.EvaluateAsync(\n            \"(() => { const e = document.scrollingElement || document.documentElement;\" +\n            \" return { y: window.scrollY, maxY: Math.max(0, e.scrollHeight - e.clientHeight) }; })()\")\n            .ConfigureAwait(false);\n        if (value == null || value.Value.ValueKind != System.Text.Json.JsonValueKind.Object\n            || !value.Value.TryGetProperty(\"y\", out var y)\n            || !value.Value.TryGetProperty(\"maxY\", out var maxY))\n            throw new StealthEvaluationError(\"<scroll-state>\");\n        return (y.GetDouble(), maxY.GetDouble());\n    }\n}\n","sourceCodeStart":103,"sourceCodeEnd":125,"githubUrl":"https://github.com/CloakHQ/CloakBrowser/blob/d6bad5de261bedf025280ace1d14e800aee13923/dotnet/src/CloakBrowser/Human/PlaywrightAdapters.cs#L103-L125","documentation":"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.","triggerScenarios":"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.","commonSituations":"Races with navigation, humanize calls after page.CloseAsync, or custom context construction that skips CloakBrowser's stealth injection.","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"],"exampleFix":"// before\nawait page.HumanScrollByAsync(300);\n\n// after\nawait page.WaitForLoadStateAsync(LoadState.DOMContentLoaded);\nif (!page.IsClosed) await page.HumanScrollByAsync(300);","handlingStrategy":"retry","validationCode":"await page.WaitForLoadStateAsync(LoadState.DOMContentLoaded);\nif (page.IsClosed) return;","typeGuard":null,"tryCatchPattern":"catch (StealthEvaluationError e) when (e.Message == \"<scroll-state>\") { settle, then retry once }","preventionTips":["Wait for load state before scroll APIs","Avoid scroll calls during teardown","Keep stealth scripts installed"],"tags":["stealth","scroll","evaluation","race-condition"],"backgroundTag":"js-evaluation-failed","analyzedSha":"d6bad5de261bedf025280ace1d14e800aee13923","analyzedAt":"2026-08-28T14:13:12.918Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}