{"record":{"id":"eed7dac6d6aceae0","repo":"chenhg5/cc-connect","slug":"qwen-asr-api-d-s","errorCode":null,"errorMessage":"qwen asr API %d: %s","messagePattern":"qwen asr API (.+?): (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/speech.go","lineNumber":183,"sourceCode":"\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"create request: %w\", err)\n\t}\n\treq.Header.Set(\"Authorization\", \"Bearer \"+q.APIKey)\n\treq.Header.Set(\"Content-Type\", \"application/json\")\n\n\tresp, err := q.Client.Do(req)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"qwen asr request: %w\", err)\n\t}\n\tdefer resp.Body.Close()\n\n\tbody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"read response: %w\", err)\n\t}\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn \"\", fmt.Errorf(\"qwen asr API %d: %s\", resp.StatusCode, string(body))\n\t}\n\n\tvar result struct {\n\t\tChoices []struct {\n\t\t\tMessage struct {\n\t\t\t\tContent string `json:\"content\"`\n\t\t\t} `json:\"message\"`\n\t\t} `json:\"choices\"`\n\t}\n\tif err := json.Unmarshal(body, &result); err != nil {\n\t\treturn \"\", fmt.Errorf(\"parse response: %w\", err)\n\t}\n\tif len(result.Choices) == 0 {\n\t\treturn \"\", fmt.Errorf(\"qwen asr: empty choices in response\")\n\t}\n\n\treturn strings.TrimSpace(result.Choices[0].Message.Content), nil\n}","sourceCodeStart":165,"sourceCodeEnd":201,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/core/speech.go#L165-L201","documentation":"Thrown by QwenSTT.Transcribe in core/speech.go when the Qwen ASR HTTP endpoint returns a non-200 status. The error embeds the status code and the raw response body so the caller can see the upstream API's reason (auth failure, bad model, oversized payload, etc.). It wraps a server-side rejection, not a local bug.","triggerScenarios":"Calling Transcribe with a Qwen provider when the POST to the Qwen chat-completions-style ASR endpoint responds with any status other than 200 — e.g. 401 invalid API key, 404 wrong model name or BaseURL path, 413 audio too large, 429 rate limit, 5xx Qwen outage.","commonSituations":"Expired or wrong DASHSCOPE/Qwen API key in config.toml; BaseURL pointing at the wrong region or missing /compatible-mode/v1; model name typo (e.g. qwen-audio-asr vs qwen2-audio); sending an audio file exceeding the API size limit; transient Qwen service errors.","solutions":["Read the status code and body in the error message to identify the upstream cause (401/403 -> fix API key; 404 -> fix BaseURL/model name; 429 -> back off; 5xx -> retry later).","Verify speech provider API key and BaseURL in config.toml against Qwen/DashScope docs.","Confirm the configured model name is a valid Qwen audio model.","Check audio file size/duration against Qwen limits and convert to a supported format (see ConvertAudioToMP3).","For 429/5xx, retry with exponential backoff."],"exampleFix":"// before: fails with opaque 401\nbaseURL = \"https://dashscope.aliyuncs.com/api/v1\" // wrong path\n// after\nbaseURL = \"https://dashscope.aliyuncs.com/compatible-mode/v1\" // correct OpenAI-compatible path, valid API key","handlingStrategy":"try-catch","validationCode":"if cfg.QwenAPIKey == \"\" { return errors.New(\"qwen: missing API key\") }\nif !strings.HasPrefix(cfg.QwenBaseURL, \"https://\") { return errors.New(\"qwen: invalid BaseURL\") }","typeGuard":null,"tryCatchPattern":"text, err := stt.Transcribe(ctx, audio)\nif err != nil {\n    if strings.Contains(err.Error(), \"qwen asr API\") {\n        // non-200: log status, surface friendly 'speech service unavailable' to user\n        slog.Warn(\"qwen asr upstream error\", \"err\", err)\n        return \"\", ErrSpeechServiceUnavailable\n    }\n    return err\n}","preventionTips":["Validate provider API keys at startup with a doctor/health check.","Pin and review BaseURL/model names against current provider docs.","Convert audio to mp3 and enforce size limits before calling Transcribe.","Add retry-with-backoff for 429/5xx status codes."],"tags":["network","http","speech-to-text","qwen","api-error"],"backgroundTag":"http-error-response","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}