kubernetes/kops · error

failed to apply resource record set: %s, err: %s

Error message

failed to apply resource record set: %s, err: %s

What it means

DigitalOcean DNS Apply() iterates the additions portion of a record change set, calling applyResourceRecordSet for each new record. If creating any record fails, the record name and underlying error are wrapped here and Apply aborts.

Source

Thrown at dnsprovider/pkg/dnsprovider/providers/do/dns.go:336

	return r
}

// Apply adds new records stored in r.additions, updates records stored
// in r.upserts and deletes records stored in r.removals
func (r *resourceRecordChangeset) Apply(ctx context.Context) error {
	// Empty changesets should be a relatively quick no-op
	if r.IsEmpty() {
		klog.V(4).Info("record change set is empty")
		return nil
	}

	klog.V(2).Info("applying changes in record change set")

	if len(r.additions) > 0 {
		for _, rrset := range r.additions {
			err := r.applyResourceRecordSet(rrset)
			if err != nil {
				return fmt.Errorf("failed to apply resource record set: %s, err: %s", rrset.Name(), err)
			}
		}

		klog.V(2).Info("record change set additions complete")
	}

	if len(r.upserts) > 0 {
		for _, rrset := range r.upserts {
			err := r.applyResourceRecordSet(rrset)
			if err != nil {
				return fmt.Errorf("failed to apply resource record set: %s, err: %s", rrset.Name(), err)
			}
		}

		klog.V(2).Info("record change set upserts complete")
	}

	if len(r.removals) > 0 {

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Check the wrapped err from the DO API response for the specific cause (404 domain, 422 validation, 401 token).
  2. Verify the domain exists in DO: `doctl compute domain list`.
  3. Validate the record's type/name/data/TTL are accepted by the DO API.
  4. Regenerate the DO API token if auth errors occur; back off on 429s.
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-flight: domain must exist and token must work
resp, err := http.Get("https://api.digitalocean.com/v2/domains/" + strings.TrimSuffix(zone, "."))
// with Authorization: Bearer <token>; a 404 here predicts Apply failure
if err != nil || resp.StatusCode == http.StatusNotFound {
    return errors.New("DO domain missing or token invalid")
}

Try / catch

err := recordSet.Apply()
if err != nil && strings.Contains(err.Error(), "failed to apply resource record set") {
    var apiErr *godo.ErrorResponse
    if errors.As(err, &apiErr) && apiErr.Response.StatusCode == 429 {
        time.Sleep(backoff) // rate limited, retry
    }
    return fmt.Errorf("DO record create failed: %w", err)
}

Prevention

When it happens

Trigger: Apply() with non-empty additions where applyResourceRecordSet fails — e.g. POST to /v2/domains/{zone}/records returns 4xx/5xx, domain doesn't exist, invalid record data/TTL, or DO API token invalid.

Common situations: The DO domain (zone) was deleted or the zone name includes the trailing dot mismatch; invalid MX/CNAME target; API token lacking write scope; DO API rate limiting (429).

Related errors


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/729d3fe59a6ec023. Report an issue: GitHub.