fish2018/pansou · error
构造搜索参数失败
Error message
构造搜索参数失败: %w
What it means
Wraps an error from buildSearchPayload, which JSON-marshals the fixed seroval payload map for the search keyword. In practice stdjson.Marshal of this map[string]interface{} structure essentially never fails (no channels/funcs/cyclic data), so this error is defensive and indicates a marshaling failure of the keyword-containing payload structure.
Solutions
- Inspect the wrapped json.Marshal error type (e.g. *json.UnsupportedTypeError) to find the offending value
- Verify the keyword passed to buildSearchPayload is a plain string (cleanText output)
- If NaN/Inf floats were introduced, sanitize them before marshaling
- Upgrade/patch the plugin if a recent change altered the payload structure
Example fix
// before
payload := map[string]interface{}{...}
return stdjson.Marshal(payload)
// after: fail fast with context on which field broke
b, err := stdjson.Marshal(payload)
if err != nil {
return nil, fmt.Errorf("marshal search payload: %w", err)
}
return b, nil Defensive patterns
Strategy: validation
Validate before calling
func keywordIsSerializable(kw string) bool {
_, err := json.Marshal(map[string]interface{}{"query": kw})
return err == nil
}
if !keywordIsSerializable(keyword) { return errors.New("keyword produces non-serializable payload") } Type guard
func isPlainString(v interface{}) bool { _, ok := v.(string); return ok } Try / catch
var typeErr *json.UnsupportedTypeError
if errors.As(err, &typeErr) {
log.Printf("payload field %s is not JSON-serializable", typeErr.Value)
} Prevention
- Keep the payload map limited to JSON-native types (string, int, map, slice)
- Sanitize keyword input before passing it into payload construction
- Add a unit test marshaling buildSearchPayload output for representative keywords
When it happens
Trigger: json.Marshal fails while serializing the payload map in buildSearchPayload — only possible if the payload structure or keyword data contains an unsupported type (e.g. NaN/Inf float, channel, func, or cyclic reference injected via a modified keyword path).
Common situations: Practically never hit by users; would appear only after a code change introduced an unsupported value into the payload map, or if keyword handling started embedding non-JSON-serializable data.
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/ecdc0343c6468bed.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/xiaokupan/xiaokupan.go:112
functionID := p.currentServerFunctionID()
results, err := p.searchWithFunctionID(client, keyword, functionID)
if err != nil {
refreshedID, refreshErr := p.refreshServerFunctionID(client, functionID)
if refreshErr != nil {
return nil, fmt.Errorf("[%s] 搜索失败: %v;刷新接口标识失败: %w", p.Name(), err, refreshErr)
}
results, err = p.searchWithFunctionID(client, keyword, refreshedID)
}
if err != nil {
return nil, fmt.Errorf("[%s] 搜索失败: %w", p.Name(), err)
}
return plugin.FilterResultsByKeyword(results, keyword), nil
}
func (p *XiaokupanPlugin) searchWithFunctionID(client *http.Client, keyword, functionID string) ([]model.SearchResult, error) {
payload, err := buildSearchPayload(keyword)
if err != nil {
return nil, fmt.Errorf("构造搜索参数失败: %w", err)
}
endpoint := fmt.Sprintf("%s/_serverFn/%s", strings.TrimRight(p.baseURL, "/"), functionID)
parsedEndpoint, err := url.Parse(endpoint)
if err != nil {
return nil, fmt.Errorf("解析搜索地址失败: %w", err)
}
query := parsedEndpoint.Query()
query.Set("payload", string(payload))
parsedEndpoint.RawQuery = query.Encode()
ctx, cancel := context.WithTimeout(context.Background(), requestTimeout)
defer cancel()
req, err := http.NewRequestWithContext(ctx, http.MethodGet, parsedEndpoint.String(), nil)
if err != nil {
return nil, fmt.Errorf("创建搜索请求失败: %w", err)
}View on GitHub (pinned to beaa561337)