chenhg5/cc-connect · error

qwen tts API error %s: %s

Error message

qwen tts API error %s: %s

What it means

The Qwen TTS API can return HTTP 200 with an application-level error encoded in the JSON envelope (non-empty "code" and "message"). Synthesize detects result.Code != "" and surfaces it as 'qwen tts API error <code>: <message>'. HTTP status alone is insufficient for this API.

Source

Thrown at core/tts.go:173

	}
	if resp.StatusCode != http.StatusOK {
		return nil, "", fmt.Errorf("qwen tts API %d: %s", resp.StatusCode, body)
	}

	var result struct {
		Code    string `json:"code"`
		Message string `json:"message"`
		Output  struct {
			Audio struct {
				URL string `json:"url"`
			} `json:"audio"`
		} `json:"output"`
	}
	if err := json.Unmarshal(body, &result); err != nil {
		return nil, "", fmt.Errorf("qwen tts: parse response: %w", err)
	}
	if result.Code != "" {
		return nil, "", fmt.Errorf("qwen tts API error %s: %s", result.Code, result.Message)
	}
	if result.Output.Audio.URL == "" {
		return nil, "", fmt.Errorf("qwen tts: empty audio URL in response")
	}

	// Download WAV from temporary URL
	audioReq, err := http.NewRequestWithContext(ctx, http.MethodGet, result.Output.Audio.URL, nil)
	if err != nil {
		return nil, "", fmt.Errorf("qwen tts: create download request: %w", err)
	}
	audioResp, err := q.Client.Do(audioReq)
	if err != nil {
		return nil, "", fmt.Errorf("qwen tts: download audio: %w", err)
	}
	defer audioResp.Body.Close()

	wavData, err := io.ReadAll(audioResp.Body)
	if err != nil {

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Read the code and message in the error and look them up in the Dashscope error-code docs.
  2. Fix the input per the message: shorten text, correct language_type, use an entitled model.
  3. Check account entitlement/quota for the chosen model in the provider console.
  4. Surface the code/message to the end user in the messaging layer instead of a generic failure.

Example fix

// before
code := result.Code // checked after unmarshal, surfaced only as error
// after
if result.Code != "" {
    slog.Warn("qwen tts business error", "code", result.Code, "msg", result.Message)
    return nil, "", fmt.Errorf("qwen tts API error %s: %s", result.Code, result.Message)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-flight input checks
if len([]rune(text)) > maxQwenInputChars {
    return fmt.Errorf("text too long for Qwen TTS (limit ~%d chars)", maxQwenInputChars)
}
if opts.LanguageType != "" && !supportedLanguageTypes[opts.LanguageType] {
    return fmt.Errorf("unsupported language_type %q", opts.LanguageType)
}

Type guard

func isQwenBusinessError(err error) (code, msg string, ok bool) {
    if err == nil { return "", "", false }
    const p = "qwen tts API error "
    if !strings.HasPrefix(err.Error(), p) { return "", "", false }
    rest := strings.TrimPrefix(err.Error(), p)
    parts := strings.SplitN(rest, ": ", 2)
    return parts[0], strings.Join(parts[1:], ": "), true
}

Try / catch

_, _, err := q.Synthesize(ctx, text, opts)
if code, msg, ok := isQwenBusinessError(err); ok {
    reply(fmt.Sprintf("TTS failed (%s): %s", code, msg))
    return
}

Prevention

When it happens

Trigger: A 200 response whose JSON contains a non-empty top-level "code" field — e.g. invalid parameter values, model not entitled, text too long, content policy rejection.

Common situations: Input text exceeding the model's length limit; unsupported language_type value; model name unavailable to the account; content filtered by the provider despite successful HTTP handling.

Related errors


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/7df0c14a65ad9a08. Report an issue: GitHub.