{"record":{"id":"9e6e16a2bf8d9e14","repo":"jeessy2/ddns-go","slug":"invalid-response-format-missing-list-field","errorCode":null,"errorMessage":"invalid response format: missing list field","messagePattern":"invalid response format: missing list field","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"dns/hipmdnsmgr.go","lineNumber":264,"sourceCode":"\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 {\n\t\t\tjsonData, _ := json.Marshal(listData)\n\t\t\tif err := json.Unmarshal(jsonData, &domains); err != nil {\n\t\t\t\treturn 0, fmt.Errorf(\"failed to parse domain list: %w\", err)\n\t\t\t}\n\t\t} else {\n\t\t\treturn 0, fmt.Errorf(\"invalid response format: missing list field\")\n\t\t}\n\tdefault:\n\t\treturn 0, fmt.Errorf(\"unknown response data format: %T\", rawData)\n\t}\n\n\t// Check if exact match is found\n\tfor _, d := range domains {\n\t\tif d.Name == domainName {\n\t\t\treturn d.ID, nil\n\t\t}\n\t}\n\n\t// Method 2: If keyword query not found, use list matching as fallback (compatible with old API)\n\t// Paginate through all domains to find the target\n\tconst pageSize = 100\n\tcurrentPage := 1\n\n\tfor {","sourceCodeStart":246,"sourceCodeEnd":282,"githubUrl":"https://github.com/jeessy2/ddns-go/blob/5874c2e6667c69357ab95079421131104bd3fcae/dns/hipmdnsmgr.go#L246-L282","documentation":"When the keyword-query response data is a JSON object, getDomainID expects a 'list' key holding the domain array. If the object has no 'list' field, this error signals the response envelope doesn't match the expected PageResult shape — i.e. the server returned an unrecognized object format.","triggerScenarios":"GET /domains?page=1&pageSize=1&keyword=<domain> returns data as an object without a 'list' key (e.g. data is the domain object directly, or {domains:[...]}, or an error object inside a code==0 envelope).","commonSituations":"DNSMgr API version change renaming or nesting the list field; a server that returns the matched domain object directly for keyword searches; misrouted request hitting a different endpoint that returns an object-shaped payload.","solutions":["Curl the endpoint and inspect the actual data object keys","Add support for the new shape in getDomainID's switch (e.g. accept v[\"domains\"] or a direct object)","Downgrade/align the DNSMgr server with the API contract this client expects","Check whether the keyword query path /domains?page=1&pageSize=1&keyword=... is still valid in your server version"],"exampleFix":"// before (server)\n{\"code\":0,\"data\":{\"domains\":[...],\"total\":1}}\n// after (client)\ncase map[string]interface{}:\n    listKey := \"list\"\n    if _, ok := v[\"list\"]; !ok {\n        listKey = \"domains\" // fallback for newer API\n    }\n    if listData, ok := v[listKey]; ok { ... }","handlingStrategy":"validation","validationCode":"// verify the API still returns the expected PageResult envelope\nvar probe struct {\n    Code int             `json:\"code\"`\n    Data json.RawMessage `json:\"data\"`\n}\n// GET /api/domains?page=1&pageSize=1 then:\nvar obj map[string]json.RawMessage\nif err := json.Unmarshal(probe.Data, &obj); err != nil {\n    return fmt.Errorf(\"data is not an object\")\n}\nif _, ok := obj[\"list\"]; !ok {\n    return fmt.Errorf(\"API no longer returns 'list' field; client upgrade needed\")\n}","typeGuard":"func hasListField(data json.RawMessage) bool {\n    var obj map[string]json.RawMessage\n    return json.Unmarshal(data, &obj) == nil && obj[\"list\"] != nil\n}","tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"missing list field\") {\n    log.Printf(\"DNSMgr response envelope changed; pin server version or upgrade ddns-go: %v\", err)\n}","preventionTips":["Pin the DNSMgr server version until the client supports its envelope","After server upgrades, curl /api/domains and confirm the {list,total} shape","Keep baseURL (DNS.ID) pointing only at genuine DNSMgr endpoints"],"tags":["go","api","schema","parsing"],"backgroundTag":"unexpected-api-response-shape","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"}