GopeedLab/gopeed · error · WebViewRpcException
TIMEOUT
TIMEOUT
Error message
navigation timeout after ${timeoutMs}ms What it means
Thrown by WebViewRpcPageSession.goto (webview_rpc_service.dart:436) when the navigation future (load event or DOM-ready, per waitUntil) does not settle within the caller-supplied timeoutMs. On timeout the service clears _navigation and throws WebViewRpcException(code: 'TIMEOUT'). The page may still finish loading afterwards — the timeout only abandons the wait.
Source
Thrown at ui/flutter/lib/app/rpc/webview_rpc_service.dart:436
);
}
final future = switch (waitStrategy) {
'domcontentloaded' => Future.any<void>([
_waitForDomReady(),
navigation.future,
]),
_ => navigation.future,
};
if (timeoutMs == null || timeoutMs <= 0) {
await future;
return;
}
await future.timeout(
Duration(milliseconds: timeoutMs),
onTimeout: () {
_navigation = null;
throw WebViewRpcException(
code: 'TIMEOUT',
message: 'navigation timeout after ${timeoutMs}ms',
);
},
);
}
Future<dynamic> execute(String expression, List<dynamic> args) async {
final controller = await _controllerOrThrow();
final requestId = 'exec-$pageId-${++_executeSeq}';
final completer = Completer<dynamic>();
_pendingExecutions[requestId] = completer;
try {
await controller.evaluateJavascript(
source: buildWebViewExecuteScript(
channelName: callbackChannelName,
requestId: requestId,
expression: expression,View on GitHub (pinned to 7b7327ffb3)
Solutions
- Switch waitUntil to "domcontentloaded", which fires much earlier than "load"
- Increase timeoutMs (e.g. 30000) for heavy pages or slow networks
- Treat TIMEOUT as non-fatal: verify readiness afterwards with page.execute of document.readyState
- Check connectivity before blaming the page; retry the goto once network is confirmed
Example fix
// before await page.goto(url, timeoutMs: 5000); // 'load' default, heavy page // after await page.goto(url, timeoutMs: 30000, waitUntil: 'domcontentloaded');
Defensive patterns
Strategy: retry
Validate before calling
if (timeoutMs !== undefined && (typeof timeoutMs !== 'number' || timeoutMs <= 0)) {
throw new TypeError('pass a positive timeoutMs or omit it');
} Try / catch
try {
await page.goto(url, timeoutMs: 30000, waitUntil: 'domcontentloaded');
} on RpcError catch (e) {
if (e.code == 'TIMEOUT') {
final state = await page.execute('document.readyState', []); // page may be usable already
if (state != 'complete') rethrow;
} else {
rethrow;
}
} Prevention
- Prefer waitUntil 'domcontentloaded' for slow or asset-heavy pages
- Size timeoutMs to the worst network you support (30s is a sane floor)
- After a TIMEOUT, check document.readyState before declaring failure — the load may be done
When it happens
Trigger: page.goto with timeoutMs: 5000 against a slow site where 'load' (all subresources) exceeds 5s; a page with hanging analytics/tracking requests; offline or throttled network; waitUntil 'load' on a page that never fires window.onload because a script blocks.
Common situations: CI runners with slow egress; mobile networks; sites with long-polling or huge assets; timeouts tuned on desktop then reused on mobile; pages that intentionally never finish loading (chat apps).
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- NAVIGATION_FAILED
- EVALUATION_FAILED
- webview navigation timeout
- webview startup timeout
- invalid navigation state
AI-assisted analysis of GopeedLab/gopeed@7b7327ffb3 (2026-08-16).
Data as JSON: /api/errors/e4af6ccbe5f4df25.
Report an issue: GitHub.