{"record":{"id":"8de6b3247632acd3","repo":"jeessy2/ddns-go","slug":"api-error-s","errorCode":null,"errorMessage":"API error: %s","messagePattern":"API error: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"dns/hipmdnsmgr.go","lineNumber":240,"sourceCode":"\t\treturn nil, err\n\t}\n\n\treturn &apiResp, nil\n}\n\n// getDomainID Get domain ID\n// Prefer using keyword parameter for direct query, with list matching as fallback\nfunc (h *HiPMDnsMgr) getDomainID(baseURL, apiToken, domainName string) (int, error) {\n\t// Method 1: Use keyword parameter for direct query (efficient)\n\tpath := fmt.Sprintf(\"/domains?page=1&pageSize=1&keyword=%s\", domainName)\n\n\tapiResp, err := h.request(baseURL, apiToken, \"GET\", path, nil)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tif apiResp.Code != 0 {\n\t\treturn 0, fmt.Errorf(\"API error: %s\", apiResp.Msg)\n\t}\n\n\tvar domains []DnsMgrDomain\n\n\t// Smart detection: support both array and object formats\n\tvar rawData interface{}\n\tif err := json.Unmarshal(apiResp.Data, &rawData); err != nil {\n\t\treturn 0, fmt.Errorf(\"failed to parse response data: %w\", err)\n\t}\n\n\tswitch v := rawData.(type) {\n\tcase []interface{}:\n\t\tjsonData, _ := json.Marshal(v)\n\t\tif err := json.Unmarshal(jsonData, &domains); err != nil {\n\t\t\treturn 0, fmt.Errorf(\"failed to parse domain list: %w\", err)\n\t\t}\n\tcase map[string]interface{}:\n\t\tif listData, ok := v[\"list\"]; ok {","sourceCodeStart":222,"sourceCodeEnd":258,"githubUrl":"https://github.com/jeessy2/ddns-go/blob/5874c2e6667c69357ab95079421131104bd3fcae/dns/hipmdnsmgr.go#L222-L258","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Read apiResp.Msg in the error text — it states the server's reason","Regenerate the API token in DNSMgr and update DNS.Secret in ddns-go config","Confirm the token's account owns or can access the configured domain","If a self-hosted DNSMgr changed its response codes, align the client with the new API contract"],"exampleFix":"// before (log)\nfailed to get domain ID: API error: unauthorized: token expired\n// after\nDNS.Secret: \"<newly generated token>\"  # update in ddns-go config and restart","handlingStrategy":"try-catch","validationCode":"// preflight: verify the token is accepted before scheduling updates\nreq, _ := http.NewRequest(\"GET\", base+\"/api/domains?page=1&pageSize=1\", nil)\nreq.Header.Set(\"Authorization\", \"Bearer \"+apiToken)\nresp, err := http.DefaultClient.Do(req)\nif err != nil { return err }\nvar r struct{ Code int `json:\"code\"`; Msg string `json:\"msg\"` }\njson.NewDecoder(resp.Body).Decode(&r)\nresp.Body.Close()\nif r.Code != 0 { return fmt.Errorf(\"token rejected: %s\", r.Msg) }","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"API error\") {\n    msg := extractAfter(err.Error(), \"API error: \")\n    if strings.Contains(strings.ToLower(msg), \"unauthor\") || strings.Contains(msg, \"token\") {\n        regenerateToken() // token invalid/expired\n    }\n    return // surface server message; don't blind-retry\n}","preventionTips":["Rotate and update the API token before expiry","Verify the token belongs to the account owning the configured domains","Log the full wrapped error to capture the server's apiResp.Msg","After DNSMgr upgrades, re-run a smoke test of an authenticated GET /domains"],"tags":["go","api","auth","dns"],"backgroundTag":"api-error-response","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"}