{"record":{"id":"51f2c731d890b6db","repo":"kubernetes/kops","slug":"cannot-apply-changes-to-forwardingrule-v","errorCode":null,"errorMessage":"cannot apply changes to ForwardingRule: %v","messagePattern":"cannot apply changes to ForwardingRule: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/gcetasks/forwardingrule.go","lineNumber":277,"sourceCode":"\t\tif changes.Labels != nil {\n\t\t\treq := compute.RegionSetLabelsRequest{\n\t\t\t\tLabelFingerprint: a.labelFingerprint,\n\t\t\t\tLabels:           e.Labels,\n\t\t\t}\n\t\t\top, err := t.Cloud.Compute().ForwardingRules().SetLabels(ctx, t.Cloud.Project(), t.Cloud.Region(), o.Name, &req)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"setting ForwardingRule labels: %w\", err)\n\t\t\t}\n\n\t\t\tif err := t.Cloud.WaitForOp(op); err != nil {\n\t\t\t\treturn fmt.Errorf(\"setting ForwardRule labels: %w\", err)\n\t\t\t}\n\n\t\t\tchanges.Labels = nil\n\t\t}\n\n\t\tif !reflect.DeepEqual(changes, &ForwardingRule{}) {\n\t\t\treturn fmt.Errorf(\"cannot apply changes to ForwardingRule: %v\", changes)\n\t\t}\n\t}\n\n\treturn nil\n}\n\ntype terraformForwardingRule struct {\n\tName                string                   `cty:\"name\"`\n\tPortRange           *string                  `cty:\"port_range\"`\n\tPorts               []string                 `cty:\"ports\"`\n\tTarget              *terraformWriter.Literal `cty:\"target\"`\n\tIPAddress           *terraformWriter.Literal `cty:\"ip_address\"`\n\tIPProtocol          string                   `cty:\"ip_protocol\"`\n\tLoadBalancingScheme *string                  `cty:\"load_balancing_scheme\"`\n\tNetwork             *terraformWriter.Literal `cty:\"network\"`\n\tSubnetwork          *terraformWriter.Literal `cty:\"subnetwork\"`\n\tBackendService      *terraformWriter.Literal `cty:\"backend_service\"`\n\tLabels              map[string]string        `cty:\"labels\"`","sourceCodeStart":259,"sourceCodeEnd":295,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/gcetasks/forwardingrule.go#L259-L295","documentation":"kOps GCE forwarding rules are effectively immutable: after applying label changes, any remaining diff between expected and actual state causes this error instead of attempting in-place modification. It tells you the cluster spec demands a field change (IP, target, network, ports, etc.) that the GCE API cannot apply to an existing rule.","triggerScenarios":"RenderGCE with a != nil where, after clearing changes.Labels, reflect.DeepEqual(changes, &ForwardingRule{}) is false — i.e. changes to Name/IPAddress/PortRange/Target/Network/etc. remain.","commonSituations":"Changing loadBalancerType, port ranges, target pool, backend service, or static IP on an existing GCE load balancer; upgrading kOps and cluster spec fields shifting; editing the cluster spec LB settings directly.","solutions":["Identify the changed fields printed in the error and revert the spec change, or accept LB recreation: `kops update cluster` will not do it in place — delete and recreate the rule (often via `kops delete instancegroup`/changing loadBalancerType and re-creating)","For API load balancers, changing the loadBalancerType typically requires recreating the load balancer resource; plan for downtime","Diff current vs desired cluster spec (`kops get -oyaml`) to see which LB field changed","Upgrade path note: some changes are handled by kOps internally by recreating tasks — ensure RuleIPAddress/observed state is refreshed before update"],"exampleFix":"// before: editing fields in place on an existing rule (unsupported)\n//   changes: {PortRange: \"8080-8080\"} -> error\n// after: delete and re-apply the load balancer so the rule is recreated\nkops delete cluster --name ... (or recreate the LB object), then\nkops update cluster --yes","handlingStrategy":"validation","validationCode":"// before updating an existing rule, check only labels differ (labels are the only mutable field)\nfunc onlyLabelsChanged(changes *ForwardingRule) bool {\n    c := *changes\n    c.Labels = nil\n    return reflect.DeepEqual(&c, &ForwardingRule{})\n}\n// if false, plan deletion+recreation of the rule instead of an update","typeGuard":null,"tryCatchPattern":"if !reflect.DeepEqual(changes, &ForwardingRule{}) {\n    return fmt.Errorf(\"cannot apply changes to ForwardingRule: %v (recreate the rule instead of updating)\", changes)\n}","preventionTips":["Treat GCE forwarding rules as immutable: expect recreation for IP/port/target/network changes","Plan load-balancer downtime when changing loadBalancerType or target","Diff `kops get cluster -oyaml` against running state before changing LB fields","Check the printed changes struct to see exactly which field triggered recreation"],"tags":["gce","forwarding-rule","immutable-resource","unsupported-change"],"backgroundTag":"immutable-resource-update","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T07:17:12.445Z"}