{"record":{"id":"d18791256508cedc","repo":"jeecgboot/JeecgBoot","slug":"statuscode","errorCode":null,"errorMessage":"旁白生成失败，状态码: {statusCode}","messagePattern":"旁白生成失败，状态码: (.+?)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/video/service/impl/VideoGenerationServiceImpl.java","lineNumber":526,"sourceCode":"        JSONObject userMsg = new JSONObject();\n        userMsg.put(\"role\", \"user\");\n        userMsg.put(\"content\", \"视频画面：\" + videoPrompt);\n\n        messages.add(systemMsg);\n        messages.add(userMsg);\n        body.put(\"messages\", messages);\n\n        HttpRequest request = HttpRequest.newBuilder()\n                .uri(URI.create(baseUrl + \"/chat/completions\"))\n                .header(\"Authorization\", \"Bearer \" + apiKey)\n                .header(\"Content-Type\", \"application/json\")\n                .POST(HttpRequest.BodyPublishers.ofString(body.toJSONString()))\n                .timeout(Duration.ofSeconds(30))\n                .build();\n\n        HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());\n        if (response.statusCode() != 200) {\n            throw new RuntimeException(\"旁白生成失败，状态码: \" + response.statusCode());\n        }\n\n        JSONObject respJson = JSON.parseObject(response.body());\n        return respJson.getJSONArray(\"choices\")\n                .getJSONObject(0)\n                .getJSONObject(\"message\")\n                .getString(\"content\")\n                .trim();\n    }\n\n    /**\n     * 使用 edge-tts 将文本转为语音\n     */\n    private void generateTtsAudio(String text, Path audioPath) throws IOException, InterruptedException {\n        ProcessBuilder pb = new ProcessBuilder(\n                edgeTtsPath,\n                \"--voice\", \"zh-CN-YunyangNeural\",\n                \"--text\", text,","sourceCodeStart":508,"sourceCodeEnd":544,"githubUrl":"https://github.com/jeecgboot/JeecgBoot/blob/96fb33f5ec68516da0b0147da06b2eb0419e063a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/video/service/impl/VideoGenerationServiceImpl.java#L508-L544","documentation":"Thrown by VideoGenerationServiceImpl.generateNarration() when the HTTP response from the GLM chat completions API (baseUrl + '/chat/completions') returns a status code other than 200. The method sends a POST request with a system+user message to generate a short narration script and checks the status code before parsing the response body.","triggerScenarios":"The GLM API (configured via aiChatConfig.aiModelVideo) returns any non-200 status: 401 (invalid API key), 403 (forbidden/quota exceeded), 429 (rate limited), 500/502/503 (server error), or 404 (wrong base URL). The method uses a 30-second timeout, so gateway timeouts may surface as a different exception (HttpTimeoutException).","commonSituations":"API key for the video narration model is missing, invalid, or expired; the apiHost configuration points to the wrong base URL; the model 'glm-4-flash' is not available on the configured endpoint; rate limiting or quota exhaustion; GLM service outage.","solutions":["Check the aiChatConfig.aiModelVideo configuration (apiKey, apiHost) in application.yml or the database config table.","Test the API key and endpoint manually with curl to identify the specific HTTP error.","Verify the model name 'glm-4-flash' is available and the account has access to it.","For 429 rate-limit errors, reduce the frequency of video generation requests or upgrade the API plan."],"exampleFix":"// before\nif (response.statusCode() != 200) {\n    throw new RuntimeException(\"旁白生成失败，状态码: \" + response.statusCode());\n}\n\n// after\nif (response.statusCode() != 200) {\n    log.error(\"GLM narration API failed. Status: {}, Body: {}\", response.statusCode(), response.body());\n    throw new RuntimeException(\"旁白生成失败，状态码: \" + response.statusCode() + \", 响应: \" + response.body());\n}","handlingStrategy":"retry","validationCode":"// Validate config before calling generateNarration\nAiChatConfig.ModelConfig config = aiChatConfig.getAiModelVideo();\nif (config == null || oConvertUtils.isEmpty(config.getApiKey()) || oConvertUtils.isEmpty(config.getApiHost())) {\n    throw new JeecgBootException(\"视频旁白AI模型未配置，请检查apiKey和apiHost\");\n}","typeGuard":"private static boolean isVideoModelConfigured(AiChatConfig.ModelConfig config) {\n    return config != null\n        && oConvertUtils.isNotEmpty(config.getApiKey())\n        && oConvertUtils.isNotEmpty(config.getApiHost());\n}","tryCatchPattern":"int maxRetries = 2;\nfor (int attempt = 0; attempt <= maxRetries; attempt++) {\n    try {\n        return generateNarration(videoPrompt);\n    } catch (RuntimeException e) {\n        if (e.getMessage().contains(\"旁白生成失败\") && attempt < maxRetries) {\n            log.warn(\"Narration generation attempt {} failed, retrying...\", attempt + 1);\n            continue;\n        }\n        log.error(\"Narration generation failed after retries\");\n        throw e;\n    }\n}","preventionTips":["Verify the aiModelVideo apiKey and apiHost are correctly configured before enabling video generation.","Test the GLM API endpoint and key with a manual curl request.","Monitor API quota and rate limits to avoid 429 errors.","Implement retry with exponential backoff for transient failures (5xx, 429).","Log the response body alongside the status code to aid debugging."],"tags":["network","ai-api","video-generation","configuration","glm"],"backgroundTag":null,"analyzedSha":"96fb33f5ec68516da0b0147da06b2eb0419e063a","analyzedAt":"2026-08-14T00:04:16.786Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}