{"record":{"id":"e4af6ccbe5f4df25","repo":"GopeedLab/gopeed","slug":"timeout","errorCode":"TIMEOUT","errorMessage":"navigation timeout after ${timeoutMs}ms","messagePattern":"navigation timeout after (.+?)ms","errorType":"error_code","errorClass":"WebViewRpcException","httpStatus":null,"severity":"error","filePath":"ui/flutter/lib/app/rpc/webview_rpc_service.dart","lineNumber":436,"sourceCode":"      );\n    }\n    final future = switch (waitStrategy) {\n      'domcontentloaded' => Future.any<void>([\n          _waitForDomReady(),\n          navigation.future,\n        ]),\n      _ => navigation.future,\n    };\n    if (timeoutMs == null || timeoutMs <= 0) {\n      await future;\n      return;\n    }\n    await future.timeout(\n      Duration(milliseconds: timeoutMs),\n      onTimeout: () {\n        _navigation = null;\n        throw WebViewRpcException(\n          code: 'TIMEOUT',\n          message: 'navigation timeout after ${timeoutMs}ms',\n        );\n      },\n    );\n  }\n\n  Future<dynamic> execute(String expression, List<dynamic> args) async {\n    final controller = await _controllerOrThrow();\n    final requestId = 'exec-$pageId-${++_executeSeq}';\n    final completer = Completer<dynamic>();\n    _pendingExecutions[requestId] = completer;\n\n    try {\n      await controller.evaluateJavascript(\n        source: buildWebViewExecuteScript(\n          channelName: callbackChannelName,\n          requestId: requestId,\n          expression: expression,","sourceCodeStart":418,"sourceCodeEnd":454,"githubUrl":"https://github.com/GopeedLab/gopeed/blob/7b7327ffb30816273a74b142cccc0bc10c5a4c67/ui/flutter/lib/app/rpc/webview_rpc_service.dart#L418-L454","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","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"],"exampleFix":"// before\nawait page.goto(url, timeoutMs: 5000); // 'load' default, heavy page\n\n// after\nawait page.goto(url, timeoutMs: 30000, waitUntil: 'domcontentloaded');","handlingStrategy":"retry","validationCode":"if (timeoutMs !== undefined && (typeof timeoutMs !== 'number' || timeoutMs <= 0)) {\n  throw new TypeError('pass a positive timeoutMs or omit it');\n}","typeGuard":null,"tryCatchPattern":"try {\n  await page.goto(url, timeoutMs: 30000, waitUntil: 'domcontentloaded');\n} on RpcError catch (e) {\n  if (e.code == 'TIMEOUT') {\n    final state = await page.execute('document.readyState', []); // page may be usable already\n    if (state != 'complete') rethrow;\n  } else {\n    rethrow;\n  }\n}","preventionTips":["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"],"tags":["dart","flutter","webview","navigation","timeout","page-goto"],"backgroundTag":null,"analyzedSha":"7b7327ffb30816273a74b142cccc0bc10c5a4c67","analyzedAt":"2026-08-16T02:51:03.250Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}