fish2018/pansou · error

marshal request failed

Error message

marshal request failed: %w

What it means

doSearch builds the Jikepan API request body as a map and serializes it with json.Marshal before POSTing. If marshaling fails, the error is wrapped as "marshal request failed" and doSearch returns no results.

Solutions

  1. Inspect the wrapped %w error to identify which value failed to marshal
  2. Restrict reqBody values to JSON-safe types (string, bool, number)
  3. Validate/sanitize ext-derived options before inserting them into reqBody

Example fix

// before
jsonData, err := json.Marshal(reqBody)
if err != nil {
	return nil, fmt.Errorf("marshal request failed: %w", err)
}

// after
if _, ok := reqBody["keyword"].(string); !ok || reqBody["keyword"] == "" {
	return nil, fmt.Errorf("invalid keyword for jikepan request")
}
jsonData, err := json.Marshal(reqBody)
if err != nil {
	return nil, fmt.Errorf("marshal request failed: %w", err)
}
Defensive patterns

Strategy: validation

Validate before calling

kw, ok := ext["keyword"].(string)
if !ok || strings.TrimSpace(kw) == "" {
	return fmt.Errorf("jikepan: keyword must be a non-empty string")
}

Type guard

func isJSONSafe(v interface{}) bool {
	switch v.(type) {
	case nil, string, bool, int, int64, float64, []interface{}, map[string]interface{}:
		return true
	}
	return false
}

Try / catch

// Go
results, err := p.doSearch(ctx, keyword, ext)
var merr *json.MarshalTypeError
if errors.As(err, &merr) {
	log.Printf("jikepan: unencodable value at %v", merr.Value)
	return nil, err
}

Prevention

When it happens

Trigger: json.Marshal(reqBody) returns an error — practically only when the dynamically-built reqBody map contains a value json cannot encode (e.g. a channel, func, or cyclic value inserted via ext options like is_all handling).

Common situations: A caller-supplied ext/option value of an unsupported type ends up in reqBody; custom marshaler on a field returns an error; otherwise extremely rare since map[string]interface{} of plain scalars always marshals.

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 fish2018/pansou@beaa561337 (2026-09-07). Data as JSON: /api/errors/0746086ad7abb24f. Report an issue: GitHub.

Appendix: source

Thrown at plugin/jikepan/jikepan.go:70

// doSearch 实际的搜索实现
func (p *JikepanAsyncV2Plugin) doSearch(client *http.Client, keyword string, ext map[string]interface{}) ([]model.SearchResult, error) {
	// 构建请求
	reqBody := map[string]interface{}{
		"name":   keyword,
		"is_all": false,
	}
	
	// 检查ext中是否包含自定义参数,如果有则使用它
	if ext != nil {
		if isAll, ok := ext["is_all"].(bool); ok && isAll {
			// 使用全量搜索,时间大约10秒
			reqBody["is_all"] = true
		}
	}
	
	jsonData, err := json.Marshal(reqBody)
	if err != nil {
		return nil, fmt.Errorf("marshal request failed: %w", err)
	}
	
	req, err := http.NewRequest("POST", JikepanAPIURL, bytes.NewBuffer(jsonData))
	if err != nil {
		return nil, fmt.Errorf("create request failed: %w", err)
	}
	
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("referer", "https://jikepan.xyz/")
	req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36")
	
	// 发送请求
	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("request failed: %w", err)
	}
	defer resp.Body.Close()
	

View on GitHub (pinned to beaa561337)