chinabugotech/hutool · error · AIException
Failed to send POST request:
Error message
Failed to send POST request:
What it means
Thrown by GeminiServiceImpl.sendPost (Gemini-specific override) on a transport-level failure of the POST. Uses x-goog-api-key auth. Hutool-http returns HTTP error statuses as a normal HttpResponse, so 4xx/5xx do NOT raise this -- only connection/socket/URL/SSL/proxy failures do. The message uses a full-width colon (:, U+FF1A). Cause is preserved.
Source
Thrown at hutool-ai/src/main/java/cn/hutool/ai/model/gemini/GeminiServiceImpl.java:494
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);
}
}
/**
* 支持流式返回的 POST 请求
*
* @param endpoint 请求地址
* @param paramMap 请求参数
* @param callback 流式数据回调函数
*/
@Override
protected void sendPostStream(String endpoint, final Map<String, Object> paramMap, final Consumer<String> callback) {
HttpURLConnection connection = null;
try {
// 创建连接
URL apiUrl = new URL(config.getApiUrl() + endpoint);
connection = (HttpURLConnection) apiUrl.openConnection();
if (config.getHasProxy()) {View on GitHub (pinned to 8870454b2a)
Solutions
- Verify config.getApiUrl() is a reachable Gemini endpoint.
- Increase setTimeout/setReadTimeout for slow operations (video, TTS).
- Inspect ex.getCause() for the underlying IOException.
- When matching this message in logs, use the full-width colon literally.
- For business errors (400/403/429), inspect the returned HttpResponse status/body.
Example fix
// before
String r = gemini.predictVideo("long prompt"); // times out
// -> Failed to send POST request:...
// after
AIConfig cfg = new AIConfigBuilder(ModelName.GEMINI.getValue())
.setApiKey(k)
.setTimeout(60_000)
.setReadTimeout(300_000) // video gen is slow
.build(); Defensive patterns
Strategy: try-catch
Validate before calling
// Generous timeout for slow Gemini POST operations (video/TTS)
if (config.getReadTimeout() < 120_000) config.setReadTimeout(300_000);
if (StrUtil.isBlank(config.getApiKey())) throw new IllegalStateException("key missing"); Try / catch
try {
return gemini.predictVideo(prompt);
} catch (AIException e) {
// message uses full-width colon (:)
if (e.getMessage().contains("Failed to send POST request")) {
Throwable root = e.getCause(); // transport IOException
// HTTP 4xx/5xx (incl. invalid key 403) are returned, not thrown here
}
throw e;
} Prevention
- Use large read timeouts for video/TTS POSTs.
- Match log filters against the full-width colon.
- Check returned HttpResponse status for business errors.
When it happens
Trigger: Gemini POST (chat, predictVideo, textToSpeech, upload start) to an unreachable apiUrl, timeout, SSL failure, or proxy failure. A malformed request body or invalid key returns an HTTP status (handled by the caller), not this exception.
Common situations: Wrong Gemini base URL; proxy blocking googleapis.com; long video/TTS generation exceeding timeout; transient outage; regional restriction.
Related errors
- Failed to send POST request:
- Failed to send GET request:
- Failed to send GET request:
- Failed to send DELETE request:
- Upload failed
AI-assisted analysis of chinabugotech/hutool@8870454b2a (2026-08-14).
Data as JSON: /api/errors/7dd2b93ebeeea5c9.
Report an issue: GitHub.