{"record":{"id":"7dd2b93ebeeea5c9","repo":"chinabugotech/hutool","slug":"failed-to-send-post-request-7dd2b9","errorCode":null,"errorMessage":"Failed to send POST request：","messagePattern":"Failed to send POST request：","errorType":"exception","errorClass":"AIException","httpStatus":null,"severity":"error","filePath":"hutool-ai/src/main/java/cn/hutool/ai/model/gemini/GeminiServiceImpl.java","lineNumber":494,"sourceCode":"\t\t\tthrow new AIException(\"Failed to send GET request: \" + e.getMessage(), e);\n\t\t}\n\t}\n\n\t@Override\n\tprotected HttpResponse sendPost(String endpoint, String paramJson) {\n\t\t//链式构建请求\n\t\ttry {\n\t\t\tfinal HttpRequest httpRequest = HttpRequest.post(config.getApiUrl() + endpoint)\n\t\t\t\t.header(Header.CONTENT_TYPE, \"application/json\")\n\t\t\t\t.header(\"x-goog-api-key\", config.getApiKey())\n\t\t\t\t.body(paramJson)\n\t\t\t\t.timeout(config.getTimeout());\n\t\t\tif (config.getHasProxy()) {\n\t\t\t\thttpRequest.setProxy(config.getProxy());\n\t\t\t}\n\t\t\treturn httpRequest.execute();\n\t\t} catch (final Exception e) {\n\t\t\tthrow new AIException(\"Failed to send POST request：\" + e.getMessage(), e);\n\t\t}\n\t}\n\n\t/**\n\t * 支持流式返回的 POST 请求\n\t *\n\t * @param endpoint 请求地址\n\t * @param paramMap 请求参数\n\t * @param callback 流式数据回调函数\n\t */\n\t@Override\n\tprotected void sendPostStream(String endpoint, final Map<String, Object> paramMap, final Consumer<String> callback) {\n\t\tHttpURLConnection connection = null;\n\t\ttry {\n\t\t\t// 创建连接\n\t\t\tURL apiUrl = new URL(config.getApiUrl() + endpoint);\n\t\t\tconnection = (HttpURLConnection) apiUrl.openConnection();\n\t\t\tif (config.getHasProxy()) {","sourceCodeStart":476,"sourceCodeEnd":512,"githubUrl":"https://github.com/chinabugotech/hutool/blob/8870454b2a0c29cc6ffd31dcf5667c8ceb2fc442/hutool-ai/src/main/java/cn/hutool/ai/model/gemini/GeminiServiceImpl.java#L476-L512","documentation":"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.","triggerScenarios":"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.","commonSituations":"Wrong Gemini base URL; proxy blocking googleapis.com; long video/TTS generation exceeding timeout; transient outage; regional restriction.","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."],"exampleFix":"// before\nString r = gemini.predictVideo(\"long prompt\"); // times out\n// -> Failed to send POST request：...\n\n// after\nAIConfig cfg = new AIConfigBuilder(ModelName.GEMINI.getValue())\n    .setApiKey(k)\n    .setTimeout(60_000)\n    .setReadTimeout(300_000) // video gen is slow\n    .build();","handlingStrategy":"try-catch","validationCode":"// Generous timeout for slow Gemini POST operations (video/TTS)\nif (config.getReadTimeout() < 120_000) config.setReadTimeout(300_000);\nif (StrUtil.isBlank(config.getApiKey())) throw new IllegalStateException(\"key missing\");","typeGuard":null,"tryCatchPattern":"try {\n    return gemini.predictVideo(prompt);\n} catch (AIException e) {\n    // message uses full-width colon （：）\n    if (e.getMessage().contains(\"Failed to send POST request\")) {\n        Throwable root = e.getCause(); // transport IOException\n        // HTTP 4xx/5xx (incl. invalid key 403) are returned, not thrown here\n    }\n    throw e;\n}","preventionTips":["Use large read timeouts for video/TTS POSTs.","Match log filters against the full-width colon.","Check returned HttpResponse status for business errors."],"tags":["network","http","transport","gemini","timeout","i18n-string"],"backgroundTag":null,"analyzedSha":"8870454b2a0c29cc6ffd31dcf5667c8ceb2fc442","analyzedAt":"2026-08-14T04:01:12.892Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}