micro/go-micro · error

failed to marshal request: %w

Error message

failed to marshal request: %w

What it means

The Together AI provider's callAPI could not JSON-marshal the request map before POSTing to /v1/chat/completions. Since the map holds plain JSON-able values, this practically means a non-serializable value (NaN/Inf float, channel, func, cyclic reference) entered the request map.

Source

Thrown at ai/together/together.go:161

	}

	return resp, nil
}

// maxToolRounds bounds the tool-execution loop in a single Generate. Each
// round is a model call plus the tools it asks for, so this is the ceiling on
// one question's cost as well as its length; it is high enough that no honest
// piece of multi-step work reaches it.
const maxToolRounds = 12

func (p *Provider) Stream(ctx context.Context, req *ai.Request, opts ...ai.GenerateOption) (ai.Stream, error) {
	return openaiapi.Stream(ctx, p.opts, req, "/v1/chat/completions")
}

func (p *Provider) callAPI(ctx context.Context, req map[string]any) (*ai.Response, map[string]any, error) {
	reqBody, err := json.Marshal(req)
	if err != nil {
		return nil, nil, fmt.Errorf("failed to marshal request: %w", err)
	}

	apiURL := strings.TrimRight(p.opts.BaseURL, "/") + "/v1/chat/completions"
	httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, apiURL, bytes.NewReader(reqBody))
	if err != nil {
		return nil, nil, fmt.Errorf("failed to create request: %w", err)
	}

	httpReq.Header.Set("Content-Type", "application/json")
	httpReq.Header.Set("Authorization", "Bearer "+p.opts.APIKey)

	httpResp, err := http.DefaultClient.Do(httpReq)
	if err != nil {
		return nil, nil, fmt.Errorf("API request failed: %w", err)
	}
	defer httpResp.Body.Close()

	respBody, _ := io.ReadAll(httpResp.Body)

View on GitHub (pinned to 24529f1404)

Solutions

  1. Validate sampling params: reject NaN/Inf for temperature/top_p before building the map
  2. Sanitize or default non-finite floats (math.IsNaN/IsInf) when constructing the request
  3. Marshal the request map in a test to reproduce the exact error message
  4. Ensure only JSON-representable values are placed into the request map

Example fix

// before
temp := computeTemperature() // may be NaN
req["temperature"] = temp
// after
if math.IsNaN(temp) || math.IsInf(temp, 0) { temp = 0.7 }
req["temperature"] = temp
Defensive patterns

Strategy: validation

Validate before calling

func sanitizeParams(params map[string]any) {
    for k, v := range params {
        if f, ok := v.(float64); ok && (math.IsNaN(f) || math.IsInf(f, 0)) {
            params[k] = nil // or a default
        }
    }
}
// call before passing the map to the provider

Type guard

func isJSONSafeFloat(f float64) bool {
    return !math.IsNaN(f) && !math.IsInf(f, 0)
}

Try / catch

resp, err := provider.Generate(ctx, req)
if err != nil && strings.Contains(err.Error(), "failed to marshal request") {
    return fmt.Errorf("non-JSON value in Together request map: %w", err)
}

Prevention

When it happens

Trigger: The req map[string]any built for the Together chat API contains a value json.Marshal rejects — e.g. NaN produced by numeric post-processing of temperature/top_p, or a custom field with an unsupported type.

Common situations: Dynamically assembled sampling params where a computation yields NaN (0/0 division), callers passing structured objects that contain funcs or channels into the request map.

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 micro/go-micro@24529f1404 (2026-09-01). Data as JSON: /api/errors/bac0c1d670062e7a. Report an issue: GitHub.