fish2018/pansou · error
[ ] 解析接口配置失败
Error message
[%s] 解析接口配置失败: %w
What it means
The bootstrap config payload from GET /test was received and XOR-decoded with bootstrapKey, but the decoded string is not valid JSON (or is not a JSON string decodable by jsonutil.UnmarshalString), so fetchConfig cannot unmarshal it into apiConfig. This indicates the encrypted/encoded payload did not decode as expected.
Solutions
- Inspect the raw response.Data and the decoded string to confirm what the server actually returned
- Verify bootstrapKey and the xorUTF16 scheme match the current server-side encoding
- Confirm the server's /test endpoint still returns the XOR-encoded JSON config; update decoding if the contract changed
- Check for proxies/CDNs rewriting the response body
Example fix
// before decoded := xorUTF16(response.Data, bootstrapKey) // stale key c := xorUTF16Decode(data, currentBootstrapKey) // after: use the key matching the deployed API
Defensive patterns
Strategy: try-catch
Validate before calling
if resp.Code == http.StatusOK && resp.Data == "" {
return errors.New("empty bootstrap payload; decoding will fail")
} Type guard
func looksLikeConfig(decoded string) bool {
var probe map[string]json.RawMessage
return json.Unmarshal([]byte(decoded), &probe) == nil && len(probe) > 0
} Try / catch
cfg, err := p.fetchConfig(ctx, client)
if err != nil {
if strings.Contains(err.Error(), "解析接口配置失败") {
log.Printf("bootstrap payload failed to decode; check key/encoding drift: %v", err)
}
return err
} Prevention
- Keep bootstrapKey in sync with the deployed server encoding
- Log the first bytes of the decoded string when unmarshal fails to detect HTML/garbage
- Pin and monitor the API version so encoding changes are caught
- Test fetchConfig against a fixture payload in CI
When it happens
Trigger: jsonutil.UnmarshalString(xorUTF16(response.Data, bootstrapKey), &config) returns an error during fetchConfig, typically because the XOR-decoded data is garbled or truncated.
Common situations: The bootstrapKey or xorUTF16 encoding no longer matches what the server sends after an API-side change; the server returned a non-config payload (e.g., HTML error body) that still passed the code==200 check; a proxy mangled the response body.
Understand the failure class
Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/9f281d1b12014955.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/yingso/yingso.go:202
results = append(results, result)
}
return plugin.FilterResultsByKeyword(results, keyword), nil
}
func (p *YingsoPlugin) fetchConfig(ctx context.Context, client *http.Client) (apiConfig, error) {
var response apiEnvelope[string]
if err := p.requestJSON(ctx, client, http.MethodGet, p.apiBaseURL+"/test", nil, &response); err != nil {
return apiConfig{}, fmt.Errorf("[%s] 获取接口配置失败: %w", p.Name(), err)
}
if response.Code != http.StatusOK || response.Data == "" {
return apiConfig{}, fmt.Errorf("[%s] 接口配置异常: code=%d msg=%s", p.Name(), response.Code, response.Msg)
}
decoded := xorUTF16(response.Data, bootstrapKey)
var config apiConfig
if err := jsonutil.UnmarshalString(decoded, &config); err != nil {
return apiConfig{}, fmt.Errorf("[%s] 解析接口配置失败: %w", p.Name(), err)
}
if config.URLVersion == "" || config.UserID == "" || config.Start < 0 || config.End <= config.Start || config.End > 24 {
return apiConfig{}, fmt.Errorf("[%s] 接口配置缺少必要字段", p.Name())
}
return config, nil
}
func (p *YingsoPlugin) search(ctx context.Context, client *http.Client, config apiConfig, keyword string) ([]searchItem, error) {
payload := searchPayload{
PageSize: pageSize,
PageNum: 1,
Title: keyword,
Root: 0,
Category: "all",
UserID: config.UserID,
}
encrypted, err := encryptPayload(payload, config)
if err != nil {View on GitHub (pinned to beaa561337)