plandex-ai/plandex · error

error marshaling request: %w

Error message

error marshaling request: %w

What it means

Before sending the streaming request, the library serializes either the OpenAI-shaped request (openaiReq) or the extended request to JSON with json.Marshal. If marshaling fails, it returns "error marshaling request: %w". For requests built from these struct types this is rare and almost always indicates a value that Go's json package cannot encode (e.g. an unsupported type such as a channel/func in an extension field).

Source

Thrown at app/server/model/client.go:329

		if extendedReq.ExtraHeaders == nil {
			extendedReq.ExtraHeaders = make(map[string]string)
		}
		extendedReq.ExtraHeaders["anthropic-beta"] = shared.AnthropicClaudeMaxBetaHeader
		extendedReq.ExtraHeaders["Authorization"] = "Bearer " + authVars[shared.AnthropicClaudeMaxTokenEnvVar]
		extendedReq.ExtraHeaders["anthropic-product"] = "claude-code"

	}

	// Marshal the request body to JSON
	var jsonBody []byte
	var err error
	if openaiReq != nil {
		jsonBody, err = json.Marshal(openaiReq)
	} else {
		jsonBody, err = json.Marshal(extendedReq)
	}
	if err != nil {
		return nil, fmt.Errorf("error marshaling request: %w", err)
	}

	// log.Println("request jsonBody", string(jsonBody))

	// Create new request
	baseUrl := baseModelConfig.BaseUrl
	url := baseUrl + "/chat/completions"

	req, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewReader(jsonBody))
	if err != nil {
		return nil, fmt.Errorf("error creating request: %w", err)
	}

	// Set required headers for streaming
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Accept", "text/event-stream")
	req.Header.Set("Cache-Control", "no-cache")
	req.Header.Set("Connection", "keep-alive")

View on GitHub (pinned to e2d772072e)

Solutions

  1. Read the wrapped %w error to identify the exact field/type that failed to marshal.
  2. Audit recently added fields on ExtendedChatCompletionRequest / ExtendedOpenAIChatCompletionRequest for json tags and serializable types.
  3. Add a unit test that marshals a fully-populated request struct to catch regressions.
  4. Implement json.Marshaler on custom types if they need special encoding.

Example fix

// before
type ExtendedChatCompletionRequest struct {
    Callback func() `json:"callback"` // unserializable
}
// after
type ExtendedChatCompletionRequest struct {
    CallbackID string `json:"callback_id,omitempty"` // serializable reference
}
Defensive patterns

Strategy: try-catch

Validate before calling

// sanity-check the request serializes before calling the library
if _, err := json.Marshal(req); err != nil {
    return fmt.Errorf("request is not JSON-serializable: %w", err)
}

Try / catch

stream, err := client.CreateChatCompletionStream(ctx, req)
if err != nil && strings.Contains(err.Error(), "error marshaling request") {
    log.Printf("request struct not serializable: %v", err)
    return fmt.Errorf("internal: request contains an unsupported field type: %w", err)
}

Prevention

When it happens

Trigger: createChatCompletionStreamExtended marshals openaiReq (provider == OpenAI, after extendedReq.ToOpenAI()) or the raw extendedReq, and json.Marshal returns an error — typically an UnsupportedTypeError from a custom extension field of unserializable type, or a Marshaler implementation returning an error.

Common situations: A custom field added to ExtendedChatCompletionRequest/ExtendedOpenAIChatCompletionRequest without json tags or with a non-serializable type (chan, func, complex); a custom MarshalJSON that errors; NaN/Inf float values in custom sampling params.

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 plandex-ai/plandex@e2d772072e (2026-09-05). Data as JSON: /api/errors/004bc07aeb4c97cd. Report an issue: GitHub.