chinabugotech/hutool · error · AIException

Failed to send GET request:

Error message

Failed to send GET request: 

What it means

Thrown by GeminiServiceImpl.sendGet (the Gemini-specific override of BaseAIService.sendGet) on a transport-level failure of HttpRequest.execute(). Unlike the base class, Gemini authenticates with the x-goog-api-key header instead of Bearer. Hutool-http does not throw on HTTP status codes, so 4xx/5xx are returned as HttpResponse and do NOT raise this; only connection/socket/URL/SSL/proxy failures do. Cause is preserved.

Source

Thrown at hutool-ai/src/main/java/cn/hutool/ai/model/gemini/GeminiServiceImpl.java:476

	 * 发送Get请求
	 * @param endpoint 请求节点
	 * @return 请求响应
	 */
	@Override
	protected HttpResponse sendGet(String endpoint) {
		//链式构建请求
		try {
			//设置超时3分钟
			final HttpRequest httpRequest = HttpRequest.get(config.getApiUrl() + endpoint)
				.header(Header.ACCEPT, "application/json")
				.header("x-goog-api-key", config.getApiKey())
				.timeout(config.getTimeout());
			if (config.getHasProxy()) {
				httpRequest.setProxy(config.getProxy());
			}
			return httpRequest.execute();
		} catch (final Exception e) {
			throw new AIException("Failed to send GET request: " + e.getMessage(), e);
		}
	}

	@Override
	protected HttpResponse sendPost(String endpoint, String paramJson) {
		//链式构建请求
		try {
			final HttpRequest httpRequest = HttpRequest.post(config.getApiUrl() + endpoint)
				.header(Header.CONTENT_TYPE, "application/json")
				.header("x-goog-api-key", config.getApiKey())
				.body(paramJson)
				.timeout(config.getTimeout());
			if (config.getHasProxy()) {
				httpRequest.setProxy(config.getProxy());
			}
			return httpRequest.execute();
		} catch (final Exception e) {
			throw new AIException("Failed to send POST request:" + e.getMessage(), e);

View on GitHub (pinned to 8870454b2a)

Solutions

  1. Confirm config.getApiUrl() points at a reachable Gemini endpoint.
  2. Verify network/proxy reachability to googleapis.com from the host.
  3. Raise setTimeout/setReadTimeout for large prompts.
  4. Inspect ex.getCause() for the real IOException.
  5. Remember an invalid key yields HTTP 403 on the response, not this -- check status separately.

Example fix

// before
AIConfig cfg = new GeminiConfigBuilder(k).build(); // default apiUrl wrong/unreachable
String r = gemini.chat("hi"); // -> Failed to send GET request

// after
AIConfig cfg = new AIConfigBuilder(ModelName.GEMINI.getValue())
    .setApiKey(k)
    .setApiUrl("https://generativelanguage.googleapis.com")
    .setTimeout(60_000)
    .build();
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate Gemini endpoint reachability before the call
String base = config.getApiUrl();
if (StrUtil.isBlank(base) || !base.contains("googleapis.com")) {
    throw new IllegalStateException("suspect Gemini apiUrl: " + base);
}
if (config.getTimeout() < 30_000) config.setTimeout(60_000);

Try / catch

try {
    return gemini.chat(prompt);
} catch (AIException e) {
    if (e.getMessage().startsWith("Failed to send GET request")) {
        Throwable root = e.getCause(); // UnknownHostException / SocketTimeoutException
        // transport only; an invalid key returns HTTP 403 on the response, not this
    }
    throw e;
}

Prevention

When it happens

Trigger: Gemini GET (chat, getVideoOperation, file metadata) against an unreachable/wrong apiUrl, connect/read timeout, SSL handshake failure, or proxy failure. Invalid API key returns HTTP 403 (not this exception).

Common situations: Wrong Gemini base URL (should be https://generativelanguage.googleapis.com); regional endpoint not reachable; corporate proxy blocking googleapis.com; timeout too low for long context; transient network outage.

Related errors


AI-assisted analysis of chinabugotech/hutool@8870454b2a (2026-08-14). Data as JSON: /api/errors/409712a90c8c1320. Report an issue: GitHub.