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
- Inspect the wrapped %w error to identify which value failed to marshal
- Restrict reqBody values to JSON-safe types (string, bool, number)
- 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
- Only put JSON-native types into reqBody
- Sanitize ext options before use
- Define reqBody as a typed struct instead of map[string]interface{}
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)