{"record":{"id":"d86df58d93702643","repo":"jeessy2/ddns-go","slug":"v","errorCode":null,"errorMessage":"生成签名失败: %v","messagePattern":"生成签名失败: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"dns/eranet.go","lineNumber":252,"sourceCode":"\n\t// 6. 重新构造最终的查询字符串(包含签名)\n\tkeys = append(keys, \"Signature\")\n\tsort.Strings(keys)\n\tvar finalQuery []string\n\tfor _, k := range keys {\n\t\tencodedKey := util.PercentEncode(k)\n\t\tencodedValue := util.PercentEncode(params[k])\n\t\tfinalQuery = append(finalQuery, encodedKey+\"=\"+encodedValue)\n\t}\n\n\treturn strings.Join(finalQuery, \"&\"), nil\n}\n\nfunc (t *Eranet) request(apiPath string, params map[string]string, method string) ([]byte, error) {\n\t// 生成签名\n\tqueryString, err := t.sign(params, method)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"生成签名失败: %v\", err)\n\t}\n\n\t// 构造完整URL\n\tbaseURL := \"https://www.eranet.com\"\n\tfullURL := baseURL + apiPath + \"?\" + queryString\n\n\t// 创建HTTP请求\n\treq, err := http.NewRequest(method, fullURL, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"创建请求失败: %v\", err)\n\t}\n\n\t// 设置请求头\n\treq.Header.Set(\"Accept\", \"application/json\")\n\n\t// 发送请求\n\tclient := t.httpClient\n\tresp, err := client.Do(req)","sourceCodeStart":234,"sourceCodeEnd":270,"githubUrl":"https://github.com/jeessy2/ddns-go/blob/5874c2e6667c69357ab95079421131104bd3fcae/dns/eranet.go#L234-L270","documentation":"Eranet.request signs every API call by building a sorted, percent-encoded canonical query string and computing an HMAC-SHA1 signature with Secret+'&'. If t.sign returns an error, request wraps it as '生成签名失败: %v' before any HTTP call is made, so create/modify/getRecordList abort immediately. In practice this signals a problem preparing the signed request rather than an API rejection.","triggerScenarios":"Any Eranet API call (create, modify, getRecordList) where the sign step fails — e.g. misconfigured/empty DNS.Secret making the signing key invalid, or a failure building the canonicalized query parameters.","commonSituations":"Missing or malformed Eranet Secret key in ddns-go config; unexpected characters in params interacting with percent-encoding; a code change to sign() introducing an error path; empty credential fields after a config migration.","solutions":["Check that the Eranet Secret (API secret key) is set and correct in the ddns-go provider config; fix or re-enter it.","Inspect the wrapped %v detail — it names the underlying signing failure; fix that cause.","Confirm the SecretId/Secret pair has no stray whitespace or newline from copy-paste.","If it persists after config fixes, verify the ddns-go Eranet driver version matches the provider's current signing (HMAC-SHA1) requirements.","Enable ddns-go logs and re-run a single record update to see the full wrapped error."],"exampleFix":"// before\nDNS := config\nSecret: \"\"            // empty -> signing fails\n// after\nSecret: \"your-eranet-secret-key\"  // valid, trimmed value","handlingStrategy":"try-catch","validationCode":"// Before calling the provider, verify required credentials are present\nif t.DNS.Secret == \"\" {\n    return errors.New(\"Eranet Secret is empty; set it in ddns-go config before syncing\")\n}","typeGuard":null,"tryCatchPattern":"body, err := t.request(apiPath, params, \"POST\")\nif err != nil {\n    if strings.Contains(err.Error(), \"生成签名失败\") {\n        // signing failed before any network call — do not retry; fix credentials/config\n        return fmt.Errorf(\"eranet signing error, check Secret config: %w\", err)\n    }\n    return err // network/HTTP errors may be retryable\n}","preventionTips":["Re-enter the Eranet Secret after any config export/import","Trim whitespace/newlines from pasted keys","Test one record update after credential changes before enabling automation","Keep the ddns-go Eranet driver updated to match current provider signing rules"],"tags":["eranet","signature","hmac","configuration","dns"],"backgroundTag":"signature-generation-failed","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"}