{"record":{"id":"f4b569a8ed3df2e3","repo":"jeessy2/ddns-go","slug":"s-f4b569","errorCode":null,"errorMessage":"%s","messagePattern":"%s","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"dns/rainyun.go","lineNumber":258,"sourceCode":"\t// 认证\n\treq.Header.Set(\"x-api-key\", rainyun.DNS.Secret)\n\tif method == http.MethodPost || method == http.MethodPatch || method == http.MethodPut {\n\t\treq.Header.Set(\"Content-Type\", \"application/json\")\n\t}\n\n\tresp, err := rainyun.httpClient.Do(req)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar apiResp RainyunResp\n\terr = util.GetHTTPResponse(resp, err, &apiResp)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif apiResp.Code != 200 {\n\t\tif apiResp.Message != \"\" {\n\t\t\treturn fmt.Errorf(\"%s\", apiResp.Message)\n\t\t}\n\t\treturn fmt.Errorf(\"Rainyun API error, code=%d\", apiResp.Code)\n\t}\n\n\tif result == nil {\n\t\treturn nil\n\t}\n\n\tdataBytes, err := json.Marshal(apiResp.Data)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn json.Unmarshal(dataBytes, result)\n}\n","sourceCodeStart":240,"sourceCodeEnd":273,"githubUrl":"https://github.com/jeessy2/ddns-go/blob/5874c2e6667c69357ab95079421131104bd3fcae/dns/rainyun.go#L240-L273","documentation":"dns/rainyun.go request() checks the Rainyun API response code and, when it is not 200 and the payload carries a non-empty Message, returns that message verbatim via fmt.Errorf(\"%s\", ...). It is a pass-through of the provider's own business-error text for getRecordList, createRecord, and patchRecord.","triggerScenarios":"Any Rainyun API call (getRecordList, createRecord, patchRecord) where the HTTP request succeeded but the JSON body has code != 200 and a non-empty Message field, e.g. invalid API key, record not found, or invalid parameters.","commonSituations":"Wrong or revoked Rainyun API key in config; subdomain not present under the configured domain; record ID stale after someone deleted the record in the Rainyun console; provider-side validation rejections.","solutions":["Read the returned message text — it is the provider's own explanation","Verify the Rainyun API key (X-API-KEY) in your configuration","Confirm the domain and subdomain exist in your Rainyun account","Re-fetch the record list before patching to ensure record IDs are current"],"exampleFix":"// before\nerr := provider.patchRecord(domain, ip)\n// after\nif err != nil && strings.Contains(err.Error(), \"api key\") {\n\tlog.Fatal(\"Rainyun API key invalid — update config\")\n} else if err != nil {\n\tlog.Printf(\"Rainyun rejected request: %v\", err)\n}","handlingStrategy":"validation","validationCode":"// verify domain/subdomain and key before calling\nif apiKey == \"\" { return errors.New(\"rainyun: missing X-API-KEY\") }\nif domain.DomainName == \"\" || domain.SubDomain == \"\" {\n\treturn errors.New(\"rainyun: domain and subdomain required\")\n}","typeGuard":null,"tryCatchPattern":"if err != nil {\n\t// err.Message is the provider text — surface it to the user verbatim\n\tlog.Printf(\"rainyun API rejected request: %v\", err)\n\treturn err\n}","preventionTips":["Keep the Rainyun API key valid and scoped to the correct account","Re-fetch records before patching so IDs are current","Match subdomain spelling exactly as configured in Rainyun"],"tags":["api-error","provider-message","rainyun"],"backgroundTag":"api-business-error-passthrough","analyzedSha":"5874c2e6667c69357ab95079421131104bd3fcae","analyzedAt":"2026-09-03T15:41:16.799Z","contentChangedAt":"2026-09-03T15:41:16.799Z","schemaVersion":2},"datasetVersion":"2026-09-11T00:17:11.886Z"}