{"record":{"id":"5b68092a11ce86cd","repo":"alibaba/spring-ai-alibaba","slug":"network-error-while-fetching-url","errorCode":null,"errorMessage":"Network error while fetching URL: ","messagePattern":"Network error while fetching URL: ","errorType":"exception","errorClass":"WebFetchException","httpStatus":null,"severity":"error","filePath":"spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/tools/WebFetchTool.java","lineNumber":342,"sourceCode":"\n\t\t\t\t@Override\n\t\t\t\tpublic Optional<javax.net.ssl.SSLSession> sslSession() {\n\t\t\t\t\treturn byteResponse.sslSession();\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic URI uri() {\n\t\t\t\t\treturn byteResponse.uri();\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic java.net.http.HttpClient.Version version() {\n\t\t\t\t\treturn byteResponse.version();\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t\tcatch (IOException e) {\n\t\t\tthrow new WebFetchException(\"Network error while fetching URL: \" + e.getMessage(), e);\n\t\t}\n\t\tcatch (InterruptedException e) {\n\t\t\tThread.currentThread().interrupt();\n\t\t\tthrow new WebFetchException(\"Request was interrupted\", e);\n\t\t}\n\t}\n\n\tprivate Optional<Charset> extractCharset(HttpResponse<?> response) {\n\t\treturn response.headers()\n\t\t\t.firstValue(\"Content-Type\")\n\t\t\t.flatMap(contentType -> {\n\t\t\t\tMatcher matcher = CHARSET_PATTERN.matcher(contentType);\n\t\t\t\tif (matcher.find()) {\n\t\t\t\t\tString charsetName = matcher.group(1);\n\t\t\t\t\ttry {\n\t\t\t\t\t\treturn Optional.of(Charset.forName(charsetName));\n\t\t\t\t\t}\n\t\t\t\t\tcatch (Exception e) {","sourceCodeStart":324,"sourceCodeEnd":360,"githubUrl":"https://github.com/alibaba/spring-ai-alibaba/blob/f82da0b50f35744c13968191be2b1cd2452ef550/spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/tools/WebFetchTool.java#L324-L360","documentation":"fetchHtml (the single-attempt HTTP call in WebFetchTool) wraps IOException from the JDK HttpClient into WebFetchException with 'Network error while fetching URL: <message>'. This is the per-attempt failure that retry logic counts; the message carries the underlying IOException text.","triggerScenarios":"HttpClient.send throws IOException — connection refused/reset, unknown host, TLS handshake failure, socket timeout, or reading the response body fails.","commonSituations":"Target site blocks the agent's user agent; DNS not resolvable inside a container; server closes keep-alive connections; SSL certificates not trusted in the JVM.","solutions":["Read the appended IOException message to identify the exact network failure.","Test the URL from the same host/network with curl.","Configure proxies and DNS for the runtime environment.","Rely on fetchHtmlWithRetry or wrap the call in your own retry with backoff for transient errors."],"exampleFix":"// before\ncatch (WebFetchException e) { throw e; }\n// after\ncatch (WebFetchException e) {\n    // e.getMessage() contains the underlying IOException message\n    return fallbackSummaryFor(url, e);\n}","handlingStrategy":"retry","validationCode":"InetAddress.getByName(URI.create(url).getHost()); // fails fast if DNS cannot resolve","typeGuard":null,"tryCatchPattern":"try {\n    String html = webFetchTool.fetch(url);\n} catch (WebFetchException e) {\n    if (e.getMessage() != null && e.getMessage().startsWith(\"Network error\")) {\n        return retryWithBackoff(url); // transient IOException\n    }\n    throw e;\n}","preventionTips":["Configure proxy env/system properties for restricted networks","Pre-resolve DNS in containers to catch misconfiguration early","Use connection timeouts that match your retry/backoff budget"],"tags":["http","ioexception","network"],"backgroundTag":"network-request-failed","analyzedSha":"f82da0b50f35744c13968191be2b1cd2452ef550","analyzedAt":"2026-09-09T15:32:42.421Z","contentChangedAt":"2026-09-09T15:32:42.421Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}