jeessy2/ddns-go · error

API error: %s

Error message

API error: %s

What it means

getDomainID receives a valid API response but its 'code' field is non-zero, meaning the DNSMgr API rejected the request at the application level (e.g. auth failure, invalid parameters). The server's message (apiResp.Msg) is surfaced verbatim.

Source

Thrown at dns/hipmdnsmgr.go:240

		return nil, err
	}

	return &apiResp, nil
}

// getDomainID Get domain ID
// Prefer using keyword parameter for direct query, with list matching as fallback
func (h *HiPMDnsMgr) getDomainID(baseURL, apiToken, domainName string) (int, error) {
	// Method 1: Use keyword parameter for direct query (efficient)
	path := fmt.Sprintf("/domains?page=1&pageSize=1&keyword=%s", domainName)

	apiResp, err := h.request(baseURL, apiToken, "GET", path, nil)
	if err != nil {
		return 0, err
	}

	if apiResp.Code != 0 {
		return 0, fmt.Errorf("API error: %s", apiResp.Msg)
	}

	var domains []DnsMgrDomain

	// Smart detection: support both array and object formats
	var rawData interface{}
	if err := json.Unmarshal(apiResp.Data, &rawData); err != nil {
		return 0, fmt.Errorf("failed to parse response data: %w", err)
	}

	switch v := rawData.(type) {
	case []interface{}:
		jsonData, _ := json.Marshal(v)
		if err := json.Unmarshal(jsonData, &domains); err != nil {
			return 0, fmt.Errorf("failed to parse domain list: %w", err)
		}
	case map[string]interface{}:
		if listData, ok := v["list"]; ok {

View on GitHub (pinned to 5874c2e666)

Solutions

  1. Read apiResp.Msg in the error text — it states the server's reason
  2. Regenerate the API token in DNSMgr and update DNS.Secret in ddns-go config
  3. Confirm the token's account owns or can access the configured domain
  4. If a self-hosted DNSMgr changed its response codes, align the client with the new API contract

Example fix

// before (log)
failed to get domain ID: API error: unauthorized: token expired
// after
DNS.Secret: "<newly generated token>"  # update in ddns-go config and restart
Defensive patterns

Strategy: try-catch

Validate before calling

// preflight: verify the token is accepted before scheduling updates
req, _ := http.NewRequest("GET", base+"/api/domains?page=1&pageSize=1", nil)
req.Header.Set("Authorization", "Bearer "+apiToken)
resp, err := http.DefaultClient.Do(req)
if err != nil { return err }
var r struct{ Code int `json:"code"`; Msg string `json:"msg"` }
json.NewDecoder(resp.Body).Decode(&r)
resp.Body.Close()
if r.Code != 0 { return fmt.Errorf("token rejected: %s", r.Msg) }

Try / catch

if err != nil && strings.Contains(err.Error(), "API error") {
    msg := extractAfter(err.Error(), "API error: ")
    if strings.Contains(strings.ToLower(msg), "unauthor") || strings.Contains(msg, "token") {
        regenerateToken() // token invalid/expired
    }
    return // surface server message; don't blind-retry
}

Prevention

When it happens

Trigger: GET /domains?page=1&pageSize=1&keyword=<domain> returns code != 0: invalid/expired Bearer token, insufficient permissions, or server-side rejection of the keyword query.

Common situations: Rotated or revoked API token still configured in ddns-go; token from a different DNSMgr account that cannot see the domain; DNSMgr server returning code 401/403-style app errors after a version upgrade.

Related errors


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