alibaba/spring-ai-alibaba · error · WebFetchException

Retry interrupted

Error message

Retry interrupted

What it means

WebFetchTool.fetchHtmlWithRetry wraps fetch failures in a WebFetchException. When the thread waiting between/inside fetch attempts is interrupted, the InterruptedException is caught, the interrupt flag is restored via Thread.currentThread().interrupt(), and this 'Retry interrupted' exception is thrown. It signals the retry loop was aborted by cancellation/shutdown rather than a network problem.

Source

Thrown at spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/tools/WebFetchTool.java:265

					logger.warn("Fetch attempt {} returned server error {} for URL: {}", attempt + 1,
							response.statusCode(), url);
					attempt++;
					continue;
				}

				return response;
			}
			catch (WebFetchException e) {
				lastException = e;
				if (e.getCause() instanceof InterruptedException) {
					throw e;
				}
				logger.warn("Fetch attempt {} failed for URL: {}: {}", attempt + 1, url, e.getMessage());
				attempt++;
			}
			catch (InterruptedException e) {
				Thread.currentThread().interrupt();
				throw new WebFetchException("Retry interrupted", e);
			}
		}

		if (lastException == null) {
			throw new WebFetchException("Failed after " + (this.maxRetries + 1) + " attempts", null);
		}
		else if (lastException instanceof WebFetchException) {
			throw new WebFetchException("Failed after " + (this.maxRetries + 1) + " attempts", lastException);
		}
		else {
			throw new WebFetchException(
					"Failed after " + (this.maxRetries + 1) + " attempts: " + lastException.getMessage(),
					lastException);
		}
	}

	private HttpResponse<String> fetchHtml(String url) {
		HttpRequest request = HttpRequest.newBuilder()

View on GitHub (pinned to f82da0b50f)

Solutions

  1. Let the interruption propagate: treat it as cancellation and stop the workflow rather than retrying or fetching again.
  2. Check upstream code that calls Thread.interrupt() (Future.cancel(true), executor shutdownNow, timeouts) and extend its timeout if cancellation is unintentional.
  3. Catch WebFetchException around the tool call and surface a clean cancellation message to the agent response.
  4. Preserve the interrupt status in your own handler (re-interrupt) so outer layers see cancellation.

Example fix

// before
String html = webFetchTool.fetch(url);
// after
try {
    String html = webFetchTool.fetch(url);
} catch (WebFetchException e) {
    if (e.getCause() instanceof InterruptedException) {
        Thread.currentThread().interrupt();
        return "fetch cancelled";
    }
    throw e;
}
Defensive patterns

Strategy: try-catch

Try / catch

try {
    String html = webFetchTool.fetch(url);
} catch (WebFetchException e) {
    if (e.getCause() instanceof InterruptedException) {
        Thread.currentThread().interrupt();
        return Optional.empty(); // treat as cancelled
    }
    throw e;
}

Prevention

When it happens

Trigger: Thread interrupt during WebFetchTool fetchHtmlWithRetry — e.g. task cancellation, executor shutdownNow, or a timeout mechanism interrupting the calling thread while the fetch/sleep between attempts is in progress.

Common situations: Calling the tool from a thread pool whose tasks get cancelled; Spring @Async with timeouts; shutting down an application while a web-fetch agent node is running; wrapping fetch in Future.get(timeout) which interrupts the worker.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09). Data as JSON: /api/errors/0dc99753de9d9263. Report an issue: GitHub.