jeecgboot/JeecgBoot · error · RuntimeException

语音生成异常: {message}

Error message

语音生成异常: {message}

What it means

A generic catch-all at the bottom of VoiceServiceImpl.textToSpeechWithUser(). It rethrows RuntimeExceptions unchanged (e.g. the TTS API failure in error 123) and wraps any other checked exception -- IOException/InterruptedException from the HTTP call or FileSystemException writing the wav -- into a RuntimeException carrying the cause message.

Source

Thrown at jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/voice/service/impl/VoiceServiceImpl.java:100

            // 调用公共TTS API生成音频
            ttsApiHelper.generateAudio(vo.getContent(), audioFile, voice, speed);

            // 返回结果
            String voiceUrl = bizPath + "/" + fileName;
            VoiceResultVo result = new VoiceResultVo();
            result.setVoiceUrl(voiceUrl);
            result.setFileName(fileName);

            // 存入Redis
            saveToRedis(vo, fileName, voiceUrl, loginUser);

            return result;
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            log.error("语音生成异常", e);
            throw new RuntimeException("语音生成异常: " + e.getMessage(), e);
        }
    }

    //update-begin---author:wangshuai ---date:2026-04-15  for:【QQYUN-14568】语音生成改为异步,支持切换菜单后重新获取结果-----------
    @Override
    public String generateAsync(VoiceGenerateVo vo) {
        String taskId = UUID.randomUUID().toString().replace("-", "");
        String taskKey = VOICE_TASK_PREFIX + taskId;

        JSONObject pending = new JSONObject();
        pending.put("status", "pending");
        redisUtil.set(taskKey, pending.toJSONString(), VOICE_TASK_TTL);

        // 在异步线程执行前先获取登录用户,避免子线程中 Shiro 上下文丢失
        LoginUser loginUser = null;
        try {
            loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        } catch (Exception e) {

View on GitHub (pinned to 96fb33f5ec)

Solutions

  1. Inspect the cause via the logged '语音生成异常' stacktrace (e.getMessage() is in the thrown text).
  2. Verify TTS apiHost/apiKey/model config (the underlying error 123 will surface for HTTP failures).
  3. Confirm jeecg.path.upload + /voice is writable and the volume has space.
  4. Raise config.getTimeout() if the error is a client-side timeout.
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-flight the upload/voice directory before TTS
Path dir = Paths.get(jeecgBaseConfig.getPath().getUpload(), "voice");
Files.createDirectories(dir);
if (!Files.isWritable(dir)) { throw new IOException("voice 目录不可写: " + dir); }

Try / catch

// The method already separates RuntimeException (rethrown) from checked (wrapped).
// Callers should catch RuntimeException and surface it to the user as a TTS failure.
try {
    return voiceService.textToSpeech(vo);
} catch (RuntimeException e) {
    log.error("语音生成失败", e);
    return Result.error("语音生成失败,请稍后重试");
}

Prevention

When it happens

Trigger: ttsApiHelper.generateAudio() raises a non-RuntimeException: HttpClient.send() hits a network/connect timeout (config.getTimeout()); the upload/voice output dir cannot be created or the wav written; the worker thread is interrupted during the blocking HTTP send.

Common situations: TTS provider unreachable from the server; upload path on a read-only/full volume; thread interrupted (async cancellation); connectTimeout (30s) exceeded.

Related errors


AI-assisted analysis of jeecgboot/JeecgBoot@96fb33f5ec (2026-08-14). Data as JSON: /api/errors/6966108138173bd6. Report an issue: GitHub.