jeessy2/ddns-go · error

failed to parse record list: %w

Error message

failed to parse record list: %w

What it means

The records page returned Code 0 but its Data payload could not be unmarshaled into DnsMgrRecordList, so getRecord fails before it can scan the page. This indicates the provider response shape does not match the struct the library expects.

Source

Thrown at dns/hipmdnsmgr.go:360

	const pageSize = 100
	currentPage := 1

	for {
		path := fmt.Sprintf("/domains/%d/records?page=%d&pageSize=%d&subdomain=%s&type=%s",
			domainID, currentPage, pageSize, subDomain, recordType)

		apiResp, err := h.request(baseURL, apiToken, "GET", path, nil)
		if err != nil {
			return nil, fmt.Errorf("paginated record query failed at page %d: %w", currentPage, err)
		}

		if apiResp.Code != 0 {
			return nil, fmt.Errorf("paginated record query API error at page %d: %s", currentPage, apiResp.Msg)
		}

		var recordList DnsMgrRecordList
		if err := json.Unmarshal(apiResp.Data, &recordList); err != nil {
			return nil, fmt.Errorf("failed to parse record list: %w", err)
		}

		// Find matching record in current page
		for _, r := range recordList.List {
			if r.Name == subDomain && r.Type == recordType {
				return &r, nil
			}
		}

		// Check if we've reached the end
		if len(recordList.List) < pageSize || (recordList.Total > 0 && currentPage*pageSize >= recordList.Total) {
			break
		}

		currentPage++

		// Safety limit: stop after 10 pages (1000 records)
		if currentPage > 10 {

View on GitHub (pinned to 5874c2e666)

Solutions

  1. Log the raw apiResp.Data to see the actual payload shape
  2. Compare the payload against DnsMgrRecordList/DnsMgrRecord field tags and update the structs or library version
  3. Upgrade the library if the provider changed its schema
  4. Check whether an intermediate proxy is rewriting error responses
  5. Make Data tolerant (omitempty/pointer fields) and handle empty payloads explicitly

Example fix

// before
var recordList DnsMgrRecordList
if err := json.Unmarshal(apiResp.Data, &recordList); err != nil {
    return nil, fmt.Errorf("failed to parse record list: %w", err)
}
// after
var recordList DnsMgrRecordList
if len(apiResp.Data) > 0 {
    if err := json.Unmarshal(apiResp.Data, &recordList); err != nil {
        return nil, fmt.Errorf("failed to parse record list (raw=%s): %w", string(apiResp.Data), err)
    }
}
Defensive patterns

Strategy: type-guard

Type guard

func isValidRecordList(data json.RawMessage) bool {
    if len(data) == 0 { return false }
    var probe struct {
        List []DnsMgrRecord `json:"list"`
    }
    return json.Unmarshal(data, &probe) == nil
}

Try / catch

rec, err := mgr.getRecord(baseURL, token, domainID, sub, rtype)
if err != nil && strings.Contains(err.Error(), "failed to parse record list") {
    // provider schema changed; pin library version or inspect raw payload before upgrading
    return fmt.Errorf("provider response format incompatible: %w", err)
}

Prevention

When it happens

Trigger: json.Unmarshal(apiResp.Data, &recordList) errors — Data is null/empty, the provider changed the JSON schema (e.g. 'list' renamed, records as object instead of array), or an HTML error page leaked into Data.

Common situations: Provider API version change altering field names, gateway/proxy returning an error page with HTTP 200, pageSize/subdomain filters causing an unexpected empty payload the library doesn't handle.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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