{"record":{"id":"0fa44026a7ee5ebb","repo":"chinabugotech/hutool","slug":"tts","errorCode":null,"errorMessage":"TTS请求失败: ","messagePattern":"TTS请求失败: ","errorType":"exception","errorClass":"AIException","httpStatus":null,"severity":"error","filePath":"hutool-ai/src/main/java/cn/hutool/ai/model/hutool/HutoolServiceImpl.java","lineNumber":124,"sourceCode":"\t@Override\n\tpublic String embeddingVision(String text, String image) {\n\t\tString paramJson = buildEmbeddingVisionRequestBody(text, image);\n\t\tfinal HttpResponse response = sendPost(EMBEDDING_VISION, paramJson);\n\t\treturn response.body();\n\t}\n\n\t@Override\n\tpublic InputStream tts(String input, final HutoolCommon.HutoolSpeech voice) {\n\t\ttry {\n\t\t\tString paramJson = buildTTSRequestBody(input, voice.getVoice());\n\t\t\tfinal HttpResponse response = sendPost(TTS, paramJson);\n\n\t\t\t// 检查响应内容类型\n\t\t\tString contentType = response.header(\"Content-Type\");\n\t\t\tif (contentType != null && contentType.startsWith(\"application/json\")) {\n\t\t\t\t// 如果是JSON响应，说明有错误\n\t\t\t\tString errorBody = response.body();\n\t\t\t\tthrow new AIException(\"TTS请求失败: \" + errorBody);\n\t\t\t}\n\t\t\t// 默认返回音频流\n\t\t\treturn response.bodyStream();\n\t\t} catch (Exception e) {\n\t\t\tthrow new AIException(\"TTS处理失败: \" + e.getMessage(), e);\n\t\t}\n\t}\n\n\t@Override\n\tpublic String stt(final File file) {\n\t\tfinal Map<String, Object> paramMap = buildSTTRequestBody(file);\n\t\tfinal HttpResponse response = sendFormData(STT, paramMap);\n\t\treturn response.body();\n\t}\n\n\n\t@Override\n\tpublic String videoTasks(String text, String image, final List<HutoolCommon.HutoolVideo> videoParams) {","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/chinabugotech/hutool/blob/8870454b2a0c29cc6ffd31dcf5667c8ceb2fc442/hutool-ai/src/main/java/cn/hutool/ai/model/hutool/HutoolServiceImpl.java#L106-L142","documentation":"Thrown by HutoolServiceImpl.tts when the TTS endpoint response has Content-Type starting with application/json, which hutool-ai interprets as an error body rather than audio. The full JSON error body is appended to the message. Note this throw happens inside a try block whose outer catch (error 16) re-wraps it, so the user-visible message is actually 'TTS处理失败: TTS请求失败: <body>'.","triggerScenarios":"Calling HutoolServiceImpl.tts(input, voice) when the upstream TTS service responds with JSON -- e.g. invalid/expired apiKey, quota exceeded, unsupported voice enum value, prompt too long, or the model/TTS feature not enabled for the account.","commonSituations":"Wrong or expired hutool AI key; the chosen HutoolSpeech voice is not supported by the account/plan; empty or over-long input text; upstream service degradation returning a JSON error.","solutions":["Read the JSON body in the message to see the upstream error code/message.","Verify the apiKey is valid and the TTS feature is enabled for the account.","Use a supported HutoolCommon.HutoolSpeech voice value.","Keep input text within the provider's length limits.","Expect the outer wrapper: the real cause text follows 'TTS处理失败: TTS请求失败: '."],"exampleFix":"// before\nInputStream audio = service.tts(\"hello\", HutoolCommon.HutoolSpeech.ALLOY);\n// upstream rejects -> TTS请求失败: {\"error\":\"invalid voice\"}\n// (then wrapped by error 16)\n\n// after -- inspect the JSON body and use a supported voice\ntry {\n    return service.tts(text, HutoolCommon.HutoolVoice.DEFAULT);\n} catch (AIException e) {\n    String body = e.getMessage().replaceFirst(\".*TTS请求失败: \", \"\");\n    log.error(\"tts upstream error body: {}\", body);\n    throw e;\n}","handlingStrategy":"try-catch","validationCode":"// Validate inputs that typically yield a JSON error body\nif (StrUtil.isBlank(input)) throw new IllegalArgumentException(\"empty tts input\");\nif (voice == null) throw new IllegalArgumentException(\"voice null\");\nif (StrUtil.isBlank(config.getApiKey())) throw new IllegalStateException(\"key missing\");","typeGuard":"static boolean isSupportedVoice(HutoolCommon.HutoolSpeech v) {\n    return v != null && java.util.EnumSet.of(\n        /* list supported voices */ HutoolCommon.HutoolSpeech.ALLOY).contains(v);\n}","tryCatchPattern":"// This inner throw is normally re-wrapped by error 16; see error 16's pattern.\n// If observed directly, the JSON body follows \"TTS请求失败: \".\nString body = e.getMessage().substring(e.getMessage().indexOf(':') + 1).trim();\nJSONObject err = JSONUtil.parseObj(body);","preventionTips":["Validate the voice enum value against supported voices.","Keep input length within provider limits.","Confirm the account has the TTS feature enabled."],"tags":["hutool","tts","http-status","error-masking"],"backgroundTag":null,"analyzedSha":"8870454b2a0c29cc6ffd31dcf5667c8ceb2fc442","analyzedAt":"2026-08-14T04:01:12.892Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}