kubernetes/kops · error

updating back-end for load-balancer %s: %w

Error message

updating back-end for load-balancer %s: %w

What it means

In LBBackend.RenderScw, when an existing backend differs from expected, kOps calls lb.ZonedAPI.UpdateBackend with the changed fields (port, protocol, algorithm, sticky sessions, proxy protocol). This error wraps a failure of that UpdateBackend call — the backend was found but could not be modified. Typically the request payload is rejected by Scaleway validation or the backend/LB is in a state that disallows updates.

Source

Thrown at upup/pkg/fi/cloudup/scalewaytasks/lb_backend.go:154

	controlPlanesIPs, err := getControlPlanesIPs(t.Cloud, expected.LoadBalancer, zone)
	if err != nil {
		return err
	}

	if actual != nil {

		_, err := lbService.UpdateBackend(&lb.ZonedAPIUpdateBackendRequest{
			Zone:                 zone,
			BackendID:            fi.ValueOf(actual.ID),
			Name:                 fi.ValueOf(actual.Name),
			ForwardProtocol:      lb.Protocol(fi.ValueOf(expected.ForwardProtocol)),
			ForwardPort:          fi.ValueOf(expected.ForwardPort),
			ForwardPortAlgorithm: lb.ForwardPortAlgorithm(fi.ValueOf(expected.ForwardPortAlgorithm)),
			StickySessions:       lb.StickySessionsType(fi.ValueOf(expected.StickySessions)),
			ProxyProtocol:        lb.ProxyProtocol(fi.ValueOf(expected.ProxyProtocol)),
		})
		if err != nil {
			return fmt.Errorf("updating back-end for load-balancer %s: %w", fi.ValueOf(actual.LoadBalancer.Name), err)
		}

		_, err = lbService.SetBackendServers(&lb.ZonedAPISetBackendServersRequest{
			Zone:      zone,
			BackendID: fi.ValueOf(actual.ID),
			ServerIP:  controlPlanesIPs,
		})
		if err != nil {
			return fmt.Errorf("updating back-end server IPs for load-balancer %s: %w", fi.ValueOf(actual.LoadBalancer.Name), err)
		}

	} else {

		backendCreated, err := lbService.CreateBackend(&lb.ZonedAPICreateBackendRequest{
			Zone:                 zone,
			LBID:                 fi.ValueOf(expected.LoadBalancer.LBID),
			Name:                 fi.ValueOf(expected.Name),
			ForwardProtocol:      lb.Protocol(fi.ValueOf(expected.ForwardProtocol)),

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Validate the cluster spec values against Scaleway enums: forward_port_algorithm (roundrobin|first|leastconn), sticky_sessions (none|cookie|table), proxy_protocol (proxy_protocol_v1|proxy_protocol_v2|proxy_protocol_unknown).
  2. Confirm the backend still exists (`scw lb backend list <lb-id>`) and re-run `kops update cluster` if it was deleted mid-apply.
  3. Wait for the LB to leave transient states (resetting/migrating) — `scw lb lb get` — then retry the apply.
  4. Check the SCW key has write permissions on the LB resource (IAM policy).
  5. If a validation error persists, run with --v=8 to inspect the exact UpdateBackend payload and fix the offending spec field.

Example fix

// before: spec value not a valid Scaleway enum
ForwardPortAlgorithm: fi.ValueOf("leastconn-tls")
// after: use an accepted Scaleway ForwardPortAlgorithm value
ForwardPortAlgorithm: fi.ValueOf("leastconn")
Defensive patterns

Strategy: validation

Validate before calling

// validate enum-ish fields against Scaleway's accepted values before apply
var validAlgorithms = map[string]bool{"roundrobin": true, "first": true, "leastconn": true}
var validSticky = map[string]bool{"none": true, "cookie": true, "table": true}
var validProxy = map[string]bool{"proxy_protocol_none": true, "proxy_protocol_v1": true, "proxy_protocol_v2": true}
if !validAlgorithms[fi.ValueOf(b.ForwardPortAlgorithm)] ||
   !validSticky[fi.ValueOf(b.StickySessions)] ||
   !validProxy[fi.ValueOf(b.ProxyProtocol)] {
    return fmt.Errorf("invalid backend enum in cluster spec")
}

Type guard

func validBackendEnums(b *LBBackend) bool {
    switch lb.ForwardPortAlgorithm(fi.ValueOf(b.ForwardPortAlgorithm)) {
    case lb.ForwardPortAlgorithmRoundrobin, lb.ForwardPortAlgorithmFirst, lb.ForwardPortAlgorithmLeastconn:
    default: return false
    }
    switch lb.ProxyProtocol(fi.ValueOf(b.ProxyProtocol)) {
    case lb.ProxyProtocolProxyProtocolNone, lb.ProxyProtocolProxyProtocolV1, lb.ProxyProtocolProxyProtocolV2, lb.ProxyProtocolProxyProtocolUnknown:
    default: return false
    }
    return true
}

Try / catch

_, err := lbService.UpdateBackend(req)
if err != nil {
    var respErr *scw.ResponseError
    if errors.As(err, &respErr) && respErr.StatusCode == 409 {
        return fmt.Errorf("LB in transient state, retry: %w", err) // retry after WaitForLb
    }
    return fmt.Errorf("updating back-end for load-balancer %s: %w", fi.ValueOf(actual.LoadBalancer.Name), err)
}

Prevention

When it happens

Trigger: lbService.UpdateBackend(&lb.ZonedAPIUpdateBackendRequest{...}) returns an error: invalid enum value cast from expected.ForwardPortAlgorithm/StickySessions/ProxyProtocol (invalid_argument), backend ID not found (deleted mid-apply), LB in 'resetting'/'migrating' transient state, or quota/validation rejection of the port/protocol combination.

Common situations: Cluster spec contains values outside Scaleway's accepted enums (e.g. proxy protocol string without the expected prefix, bad forward-port-algorithm like 'leastconn' vs 'roundrobin'/'first'/'leastconn' spelling); concurrent apply racing a Scaleway LB maintenance state; backend deleted manually during apply; permissions lacking lb edit rights.

Related errors


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