chenhg5/cc-connect · error

qwen tts: marshal request: %w

Error message

qwen tts: marshal request: %w

What it means

QwenTTS.Synthesize builds the JSON request body (model, input text, optional language_type) with json.Marshal. If marshaling fails it wraps the error as 'qwen tts: marshal request'. This is nearly impossible with the fixed struct shape and typically indicates a programming-level serialization problem.

Source

Thrown at core/tts.go:136

func (q *QwenTTS) Synthesize(ctx context.Context, text string, opts TTSSynthesisOpts) ([]byte, string, error) {
	voice := opts.Voice
	if voice == "" {
		voice = "Cherry"
	}
	reqBody := map[string]any{
		"model": q.Model,
	}
	input := map[string]any{
		"text":  text,
		"voice": voice,
	}
	if opts.LanguageType != "" {
		input["language_type"] = opts.LanguageType
	}
	reqBody["input"] = input
	jsonData, err := json.Marshal(reqBody)
	if err != nil {
		return nil, "", fmt.Errorf("qwen tts: marshal request: %w", err)
	}

	req, err := http.NewRequestWithContext(ctx, http.MethodPost, q.BaseURL, bytes.NewReader(jsonData))
	if err != nil {
		return nil, "", fmt.Errorf("qwen tts: create request: %w", err)
	}
	req.Header.Set("Authorization", "Bearer "+q.APIKey)
	req.Header.Set("Content-Type", "application/json")

	resp, err := q.Client.Do(req)
	if err != nil {
		return nil, "", fmt.Errorf("qwen tts: request: %w", err)
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, "", fmt.Errorf("qwen tts: read response: %w", err)

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Inspect the wrapped error and the values placed into the request body; remove any non-JSON-serializable values.
  2. Ensure opts fields (Text, LanguageType) are plain strings.
  3. This is an internal bug if you only pass normal string options — file/debug the code constructing reqBody.

Example fix

// before
reqBody["input"] = someRuntimeValue // may be unserializable
// after
reqBody["input"] = fmt.Sprintf("%v", someRuntimeValue)
Defensive patterns

Strategy: try-catch

Validate before calling

if opts.Text == "" || opts.LanguageType == "" && false {
    // only plain strings allowed in request body
}
// ensure any custom values injected into the request are JSON-encodable
if err := json.Marshal(reqBody); err != nil { /* fix value types before calling Synthesize */ }

Try / catch

audio, url, err := q.Synthesize(ctx, text, opts)
if err != nil {
    var se *fmt.wrapError
    if errors.As(err, &se) && strings.Contains(err.Error(), "marshal request") {
        slog.Error("qwen tts request construction bug", "err", err)
    }
    return err
}

Prevention

When it happens

Trigger: json.Marshal(reqBody) returns an error — for a map[string]any/struct of plain strings this effectively only happens if an unsupported value type (e.g. a channel, func, or cyclic value) was injected into reqBody.

Common situations: Custom code that mutates the request map with non-JSON-serializable values before Synthesize is called; generics/refactor code placing a wrong-typed value into the options.

Understand the failure class

Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.

Related errors


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