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
- Confirm config.getApiUrl() points at a reachable Gemini endpoint.
- Verify network/proxy reachability to googleapis.com from the host.
- Raise setTimeout/setReadTimeout for large prompts.
- Inspect ex.getCause() for the real IOException.
- 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
- Set the Gemini base URL explicitly.
- Allow egress to googleapis.com (proxy/firewall).
- Distinguish transport errors from HTTP 403 key errors.
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
- Failed to send POST request:
- Failed to send GET request:
- Failed to send POST request:
- Failed to send DELETE request:
- Upload failed
AI-assisted analysis of chinabugotech/hutool@8870454b2a (2026-08-14).
Data as JSON: /api/errors/409712a90c8c1320.
Report an issue: GitHub.