chinabugotech/hutool · error · AIException
Failed to send POST request:
Error message
Failed to send POST request:
What it means
Thrown by BaseAIService.sendPost on a transport-level failure of HttpRequest.execute(). Hutool-http returns HTTP error statuses as a normal HttpResponse, so 4xx/5xx do NOT raise this -- only connection/socket/URL/SSL/proxy errors do. Note the message uses a full-width colon character (:, U+FF1A), not an ASCII colon, which matters if you filter or match the string. The cause is preserved.
Source
Thrown at hutool-ai/src/main/java/cn/hutool/ai/core/BaseAIService.java:94
* @param endpoint 请求节点
* @param paramJson 请求参数json
* @return 请求响应
*/
protected HttpResponse sendPost(final String endpoint, final String paramJson) {
//链式构建请求
try {
HttpRequest httpRequest = HttpRequest.post(config.getApiUrl() + endpoint)
.header(Header.CONTENT_TYPE, "application/json")
.header(Header.ACCEPT, "application/json")
.header(Header.AUTHORIZATION, "Bearer " + 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);
}
}
/**
* 发送表单请求
* @param endpoint 请求节点
* @param paramMap 请求参数map
* @return 请求响应
*/
protected HttpResponse sendFormData(final String endpoint, final Map<String, Object> paramMap) {
//链式构建请求
try {
//设置超时3分钟
HttpRequest httpRequest = HttpRequest.post(config.getApiUrl() + endpoint)
.header(Header.CONTENT_TYPE, "multipart/form-data")
.header(Header.ACCEPT, "application/json")
.header(Header.AUTHORIZATION, "Bearer " + config.getApiKey())View on GitHub (pinned to 8870454b2a)
Solutions
- Confirm config.getApiUrl() + endpoint resolves and accepts POST.
- Raise setTimeout/setReadTimeout for slow generation.
- Inspect ex.getCause() for the underlying IOException.
- If matching this message in logs, use the full-width colon (:) literally.
- For HTTP business errors, read response.getStatus()/body() on the success path instead.
Example fix
// before
HttpResponse resp = service.sendPost("/v1/chat/completions", json);
// transport fails -> Failed to send POST request:...
// after
AIConfig cfg = new AIConfigBuilder(ModelName.OPENAI.getValue())
.setApiKey(k).setApiUrl("https://api.openai.com")
.setTimeout(60_000).setReadTimeout(120_000).build();
HttpResponse resp = service.sendPost("/v1/chat/completions", json);
if (!resp.isOk()) { /* handle 4xx/5xx body */ } Defensive patterns
Strategy: try-catch
Validate before calling
// Validate URL + timeout before the POST
String base = config.getApiUrl();
if (StrUtil.isBlank(base)) throw new IllegalStateException("apiUrl blank");
if (config.getTimeout() < 10_000) config.setTimeout(30_000); Try / catch
try {
return service.sendPost(endpoint, json);
} catch (AIException e) {
// NOTE: message uses full-width colon (:)
if (e.getMessage().contains("Failed to send POST request")) {
Throwable root = e.getCause(); // real IOException
// transport failure only; HTTP 4xx/5xx are returned, not thrown
}
throw e;
} Prevention
- Match the message with the full-width colon if filtering logs.
- Set generous read timeouts for generation endpoints.
- Check response.getStatus() separately for business errors.
When it happens
Trigger: POST to an unreachable/malformed apiUrl, connect/read timeout, SSL handshake failure, or proxy failure during chat/embeddings calls on models inheriting BaseAIService.sendPost (deepseek, openai, doubao, grok, hutool). A large or malformed paramJson causes a different error path, not this one.
Common situations: Wrong base URL; network outage; timeout too low; reverse-proxy rejecting the path; self-signed cert. Invalid apiKey or rate-limit returns an HTTP status (handled by the caller), not this exception.
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/0e07622cfa84a502.
Report an issue: GitHub.