{"record":{"id":"4c5fe1cc884d6797","repo":"fish2018/pansou","slug":"s-4c5fe1","errorCode":null,"errorMessage":"[%s] 接口配置缺少必要字段","messagePattern":"\\[(.+?)\\] 接口配置缺少必要字段","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/yingso/yingso.go","lineNumber":205,"sourceCode":"\treturn plugin.FilterResultsByKeyword(results, keyword), nil\n}\n\nfunc (p *YingsoPlugin) fetchConfig(ctx context.Context, client *http.Client) (apiConfig, error) {\n\tvar response apiEnvelope[string]\n\tif err := p.requestJSON(ctx, client, http.MethodGet, p.apiBaseURL+\"/test\", nil, &response); err != nil {\n\t\treturn apiConfig{}, fmt.Errorf(\"[%s] 获取接口配置失败: %w\", p.Name(), err)\n\t}\n\tif response.Code != http.StatusOK || response.Data == \"\" {\n\t\treturn apiConfig{}, fmt.Errorf(\"[%s] 接口配置异常: code=%d msg=%s\", p.Name(), response.Code, response.Msg)\n\t}\n\n\tdecoded := xorUTF16(response.Data, bootstrapKey)\n\tvar config apiConfig\n\tif err := jsonutil.UnmarshalString(decoded, &config); err != nil {\n\t\treturn apiConfig{}, fmt.Errorf(\"[%s] 解析接口配置失败: %w\", p.Name(), err)\n\t}\n\tif config.URLVersion == \"\" || config.UserID == \"\" || config.Start < 0 || config.End <= config.Start || config.End > 24 {\n\t\treturn apiConfig{}, fmt.Errorf(\"[%s] 接口配置缺少必要字段\", p.Name())\n\t}\n\treturn config, nil\n}\n\nfunc (p *YingsoPlugin) search(ctx context.Context, client *http.Client, config apiConfig, keyword string) ([]searchItem, error) {\n\tpayload := searchPayload{\n\t\tPageSize: pageSize,\n\t\tPageNum:  1,\n\t\tTitle:    keyword,\n\t\tRoot:     0,\n\t\tCategory: \"all\",\n\t\tUserID:   config.UserID,\n\t}\n\tencrypted, err := encryptPayload(payload, config)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 生成搜索参数失败: %w\", p.Name(), err)\n\t}\n","sourceCodeStart":187,"sourceCodeEnd":223,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/yingso/yingso.go#L187-L223","documentation":"The bootstrap config decoded and unmarshalled successfully into apiConfig, but its contents failed sanity validation: URLVersion or UserID is empty, Start is negative, End <= Start, or End > 24. fetchConfig refuses to continue with a config that cannot produce valid search URLs or paging windows.","triggerScenarios":"After unmarshalling, config.URLVersion == \"\" || config.UserID == \"\" || config.Start < 0 || config.End <= config.Start || config.End > 24 in fetchConfig.","commonSituations":"The server-side config schema changed (fields renamed, moved, or removed) so they unmarshal as zero values; the XOR decode produced valid JSON of the wrong shape; the server returns partial config during maintenance or for deprecated API versions.","solutions":["Dump the decoded JSON and compare its field names/types against the apiConfig struct tags","Update the apiConfig struct (json tags) to match the current server schema","Confirm the account/API version still provides UserID and URLVersion","Add a log of the raw config to catch silent schema drift early"],"exampleFix":"// before\ntype apiConfig struct {\n    URLVersion string `json:\"url_version\"`\n}\n// after\ntype apiConfig struct {\n    URLVersion string `json:\"urlVersion\"`\n    UserID     string `json:\"userId\"`\n    Start      int    `json:\"start\"`\n    End        int    `json:\"end\"`\n}","handlingStrategy":"validation","validationCode":"func validConfig(c apiConfig) bool {\n    return c.URLVersion != \"\" && c.UserID != \"\" &&\n        c.Start >= 0 && c.End > c.Start && c.End <= 24\n}","typeGuard":"func (c apiConfig) OK() bool {\n    return c.URLVersion != \"\" && c.UserID != \"\" &&\n        c.Start >= 0 && c.End > c.Start && c.End <= 24\n}","tryCatchPattern":"cfg, err := p.fetchConfig(ctx, client)\nif err != nil {\n    if strings.Contains(err.Error(), \"缺少必要字段\") {\n        log.Printf(\"yingso config schema drift detected: %+v\", cfg)\n    }\n    return err\n}","preventionTips":["Compare decoded JSON keys against apiConfig json tags after any API update","Log the raw decoded config on validation failure to spot renamed fields","Write a golden-file test unmarshalling a live /test payload snapshot","Fail fast at startup so schema drift is caught before serving searches"],"tags":["validation","config","api","schema"],"backgroundTag":"missing-required-config-field","analyzedSha":"beaa56133755a548ebc51b090b3816e2ae044aa6","analyzedAt":"2026-09-07T00:31:18.025Z","contentChangedAt":"2026-09-07T00:31:18.025Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}