{"record":{"id":"4fc58d897d3dc673","repo":"GopeedLab/gopeed","slug":"evaluation-failed","errorCode":"EVALUATION_FAILED","errorMessage":"e.toString()","messagePattern":"e\\.toString\\(\\)","errorType":"error_code","errorClass":"WebViewRpcException","httpStatus":null,"severity":"error","filePath":"ui/flutter/lib/app/rpc/webview_rpc_service.dart","lineNumber":461,"sourceCode":"  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,\n          args: args,\n        ),\n      );\n    } catch (e) {\n      _pendingExecutions.remove(requestId);\n      throw WebViewRpcException(\n        code: 'EVALUATION_FAILED',\n        message: e.toString(),\n      );\n    }\n\n    try {\n      final result = await completer.future.timeout(\n        const Duration(seconds: 30),\n        onTimeout: () {\n          _pendingExecutions.remove(requestId);\n          throw WebViewRpcException(\n            code: 'TIMEOUT',\n            message: 'javascript execution timeout',\n          );\n        },\n      );\n      return result;\n    } finally {\n      _pendingExecutions.remove(requestId);","sourceCodeStart":443,"sourceCodeEnd":479,"githubUrl":"https://github.com/GopeedLab/gopeed/blob/7b7327ffb30816273a74b142cccc0bc10c5a4c67/ui/flutter/lib/app/rpc/webview_rpc_service.dart#L443-L479","documentation":"Thrown by WebViewRpcPageSession.execute (webview_rpc_service.dart:461) when InAppWebViewController.evaluateJavascript throws while injecting the wrapper script — a native/channel-level failure, not a JavaScript error in your expression (those flow back through the callback channel and surface as error 38). The pending completer is removed and the exception string is wrapped as EVALUATION_FAILED.","triggerScenarios":"Calling 'page.execute' while the webview is being torn down (dispose races the call); executing on a page whose native controller died; platform channel errors on Android/iOS when the WebView is detached. Contrast: a syntax error in 'expression' posts back via the bridge and raises error 38 instead.","commonSituations":"Fire-and-forget execute calls racing page.close or app backgrounding on mobile (Android destroys the webview); memory pressure reclaiming the headless webview; executing immediately after page.open before the controller fully attaches.","solutions":["Await page.open's returned pageId and give the first goto/execute a small readiness check before heavy use","Catch EVALUATION_FAILED whose message is a PlatformException, reopen the page (page.open + goto), and re-run the expression once","Serialize close/execute per page in the client so dispose cannot race an in-flight execute","Read e.toString() in the message to identify the platform cause before retrying"],"exampleFix":"// before\npage.execute('window.__poll()', []); // unawaited, races page.close()\n\n// after\ntry {\n  await page.execute('window.__poll()', []);\n} on RpcError catch (e) {\n  if (e.code != 'EVALUATION_FAILED') rethrow;\n  await reopenAndNavigate(); // page.open + page.goto, then retry once\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  return await page.execute(expression, args);\n} on RpcError catch (e) {\n  if (e.code == 'EVALUATION_FAILED' && !e.message.contains('Error:')) {\n    // native PlatformException, not a JS error: reopen page and retry once\n    await reopenPage();\n    return await page.execute(expression, args);\n  }\n  rethrow;\n}","preventionTips":["Serialize close/execute per page so dispose cannot race an in-flight execute","Distinguish native failures (message is a PlatformException string) from JS errors (message is a browser error)","Reopen-and-retry once is usually enough; persistent failure means the webview environment is broken"],"tags":["dart","flutter","webview","javascript","evaluation","race-condition","page-execute"],"backgroundTag":null,"analyzedSha":"7b7327ffb30816273a74b142cccc0bc10c5a4c67","analyzedAt":"2026-08-16T02:51:03.250Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}