jeessy2/ddns-go · error

API请求失败,状态码: %d, 响应: %s

Error message

API请求失败,状态码: %d, 响应: %s

What it means

Thrown by Eranet.request when the eranet.com API returns an HTTP status code other than 200. The error includes the numeric status and the raw response body, so the API's own error payload (often JSON explaining auth/signature problems) is embedded in the message. Affects create, modify, and getRecordList.

Source

Thrown at dns/eranet.go:284

	req.Header.Set("Accept", "application/json")

	// 发送请求
	client := t.httpClient
	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("请求失败: %v", err)
	}
	defer resp.Body.Close()

	// 读取响应
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("读取响应失败: %v", err)
	}

	// 检查HTTP状态码
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("API请求失败,状态码: %d, 响应: %s", resp.StatusCode, string(body))
	}

	return body, nil
}

View on GitHub (pinned to 5874c2e666)

Solutions

  1. Read the embedded response body in the error message — it usually states the API-level cause
  2. Verify the API key/secret configured for the eranet provider are correct and active
  3. Check system time (NTP) — the request Signature depends on timestamps and fails on skew
  4. If status is 5xx, retry later — it is an eranet-side outage
  5. Compare parameter values (domain, subdomain, record type) against eranet API docs

Example fix

// before
// opaque handling of error
return err
// after
var apiErr struct {
    Code int    `json:"code"`
    Msg  string `json:"message"`
}
if json.Unmarshal(body, &apiErr) == nil && apiErr.Msg != "" {
    return fmt.Errorf("API请求失败,状态码: %d, 原因: %s", resp.StatusCode, apiErr.Msg)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// validate credentials & params before calling the API
if apiKey == "" || apiSecret == "" {
    return fmt.Errorf("eranet credentials missing")
}
if strings.TrimSpace(domainName) == "" {
    return fmt.Errorf("domain name required")
}

Type guard

func isEranetStatusError(err error) (statusCode int, body string, ok bool) {
    // "API请求失败,状态码: %d, 响应: %s"
    const prefix = "API请求失败,状态码: "
    msg := err.Error()
    i := strings.Index(msg, prefix)
    if i < 0 {
        return 0, "", false
    }
    rest := msg[i+len(prefix):]
    j := strings.Index(rest, ", 响应: ")
    if j < 0 {
        return 0, "", false
    }
    code, e := strconv.Atoi(strings.TrimSpace(rest[:j]))
    if e != nil {
        return 0, "", false
    }
    return code, rest[j+len(", 响应: "):], true
}

Try / catch

_, err := eranetClient.GetRecordList(domain)
if err != nil {
    if code, body, ok := isEranetStatusError(err); ok {
        switch {
        case code == 401 || code == 403:
            return fmt.Errorf("check eranet API credentials: %s", body)
        case code >= 500:
            return retryWithBackoff(3, func() error { _, err = eranetClient.GetRecordList(domain); return err })
        default:
            return fmt.Errorf("eranet rejected request (%d): %s", code, body)
        }
    }
    return err
}

Prevention

When it happens

Trigger: Any non-200 response from https://www.eranet.com: 401/403 for bad API credentials, 4xx for invalid parameters or signature mismatch, 5xx for eranet server errors, or 404 from a wrong apiPath.

Common situations: Wrong or expired eranet API key/secret in config; system clock skew breaking the HMAC Signature; parameter values rejected by the API (invalid domain/record); eranet service outage returning 5xx.

Related errors


AI-assisted analysis of jeessy2/ddns-go@5874c2e666 (2026-09-03). Data as JSON: /api/errors/3a373a9f7d28c261. Report an issue: GitHub.