CloakHQ/CloakBrowser · error · ActionabilityError
timeout
timeout
Error message
timeout
What it means
The actionability polling loop in EnsureActionableAsync ran out of time before even one DOM check completed, and no earlier element error was recorded to rethrow. It means the deadline elapsed with zero successful StealthDom.ActionableAsync evaluations — the element state was never assessed.
Source
Thrown at dotnet/src/CloakBrowser/Human/Actionability.cs:158
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(
stealth, selector).ConfigureAwait(false);
if (status == StealthStatus.Unsupported)
throw new UnsupportedHumanizeSelectorError(selector);
if (status == StealthStatus.EvaluationFailed)
throw new StealthEvaluationError(selector);
if (status == StealthStatus.NotFound)
throw new ElementNotAttachedError(selector);
if (status != StealthStatus.Ok || snapshot == null)
throw new StealthEvaluationError(selector);
var value = snapshot.Value;
if (checks.Contains("visible") && !value.Visible)
throw new ElementNotVisibleError(selector);View on GitHub (pinned to d6bad5de26)
Solutions
- Increase timeoutMs to a realistic value (hundreds of ms to seconds).
- Ensure the page is settled (not navigating) before starting actionability checks.
- Profile the isolated-world round-trip time; if it routinely exceeds the timeout, fix browser performance or headless-mode issues.
- If an earlier element error exists it is rethrown instead — address that underlying error first.
Example fix
// before await Actionability.EnsureActionableAsync(page, selector, stealth, timeoutMs: 5); // after await Actionability.EnsureActionableAsync(page, selector, stealth, timeoutMs: 5000);
Defensive patterns
Strategy: retry
Validate before calling
if (timeoutMs < 250) throw new ArgumentOutOfRangeException(nameof(timeoutMs), "allow at least one DOM round-trip");
Try / catch
catch (ActionabilityError ex) when (ex.Code == "timeout")
{
await Task.Delay(200);
await Actionability.EnsureActionableAsync(page, selector, stealth, timeoutMs: Math.Max(timeoutMs * 4, 5000));
} Prevention
- Never pass near-zero timeouts; budget >= 1s for the first isolated-world round-trip.
- Ensure the page is idle before starting actionability polling.
- Warm up the isolated world once per page to avoid first-evaluation latency.
When it happens
Trigger: Calling EnsureActionableAsync with a timeoutMs too small for even one round-trip to the isolated world (remainingMs <= 0 on the first iteration with lastError == null), or the browser/CDP connection being so slow the first check never completes.
Common situations: Passing timeoutMs of 0 or a few milliseconds; overloaded browser or CPU-starved worker making the first CDP evaluation exceed the budget; navigating while the check starts; unit tests with artificially tiny timeouts.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Element ${selector} failed timeout check: timeout expired be
- Invalid browser version pin. Use a full numeric Chromium ver
- Isolated-world DOM evaluation failed for ${selector}
- Element ${selector} failed attached check: element not found
- Element ${selector} failed visible check: element is not vis
AI-assisted analysis of CloakHQ/CloakBrowser@d6bad5de26 (2026-08-28).
Data as JSON: /api/errors/95a0a3aaf1bbdc27.
Report an issue: GitHub.