Tencent/WeKnora · error

failed to marshal request: %w

Error message

failed to marshal request: %w

What it means

KeenableProvider.Search failed to serialize its keenableSearchRequest (Query + Mode "pro") to JSON before building the HTTP request. Because the struct contains only basic types this error is practically unreachable unless the struct gains unsupported fields (e.g. channels, funcs) or a custom marshaller misbehaves.

Source

Thrown at internal/infrastructure/web_search/keenable.go:84

) ([]*types.WebSearchResult, error) {
	if len(query) == 0 {
		return nil, fmt.Errorf("query is empty")
	}
	if maxResults <= 0 {
		maxResults = defaultKeenableResults
	}

	// Keyless by default; a configured key switches to the authenticated path.
	path := "/v1/search/public"
	if p.apiKey != "" {
		path = "/v1/search"
	}
	endpoint := p.baseURL + path
	logger.Infof(ctx, "[WebSearch][Keenable] query=%q maxResults=%d url=%s", query, maxResults, endpoint)

	bodyBytes, err := json.Marshal(keenableSearchRequest{Query: query, Mode: "pro"})
	if err != nil {
		return nil, fmt.Errorf("failed to marshal request: %w", err)
	}

	req, err := http.NewRequestWithContext(ctx, "POST", endpoint, bytes.NewReader(bodyBytes))
	if err != nil {
		return nil, fmt.Errorf("failed to create request: %w", err)
	}
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Accept", "application/json")
	req.Header.Set("X-Keenable-Title", keenableTitle)
	if p.apiKey != "" {
		req.Header.Set("X-API-Key", p.apiKey)
	}

	resp, err := p.client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("failed to execute request: %w", err)
	}
	defer resp.Body.Close()

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Inspect the wrapped error — it names the unsupported value/type in the request struct.
  2. Remove or replace fields of types json.Marshal cannot encode (chan, func, complex).
  3. If a custom MarshalJSON exists, fix it to return valid JSON or nil error.
  4. Rebuild the binary to ensure the struct definition matches expectations.

Example fix

// before
type keenableSearchRequest struct {
    Query string
    Mode  string
    Callback func() // unsupported by json.Marshal
}
// after
type keenableSearchRequest struct {
    Query string `json:"query"`
    Mode  string `json:"mode"`
}
Defensive patterns

Strategy: try-catch

Try / catch

if err != nil && strings.Contains(err.Error(), "failed to marshal request") {
    log.Errorf("keenable request struct not JSON-serializable: %v", err)
    return nil, fmt.Errorf("internal error building keenable request: %w", err)
}

Prevention

When it happens

Trigger: json.Marshal(keenableSearchRequest{...}) returns an error — normally impossible for plain string/int fields; possible after adding fields of unsupported types (chan, func, cyclic pointers).

Common situations: A developer extended keenableSearchRequest with an unsupported field type; a custom MarshalJSON returns an error; corrupted build with a stale struct definition.

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 Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/71013929d2920d9c. Report an issue: GitHub.