kubernetes/kops · error
applying changes to Router is unsupported: %s
Error message
applying changes to Router is unsupported: %s
What it means
RenderGCE raises this when a Router task runs in 'update' mode (the router already exists) but the computed changes are not an empty diff — kOps does not implement in-place updates for GCE Cloud Routers, so any drift is rejected rather than applied. The %s is the router's name.
Source
Thrown at upup/pkg/fi/cloudup/gcetasks/router.go:180
},
}
for _, subnet := range e.Subnetworks {
router.Nats[0].Subnetworks = append(router.Nats[0].Subnetworks, &compute.RouterNatSubnetworkToNat{
Name: subnet.URL(project, region),
SourceIpRangesToNat: []string{subnetNatAllIPRanges},
})
}
op, err := t.Cloud.Compute().Routers().Insert(project, region, router)
if err != nil {
return fmt.Errorf("error creating Router: %w", err)
}
if err := t.Cloud.WaitForOp(op); err != nil {
return fmt.Errorf("error waiting for router creation: %w", err)
}
} else {
if !reflect.DeepEqual(changes, &Router{}) {
return fmt.Errorf("applying changes to Router is unsupported: %s", *e.Name)
}
}
return nil
}
type terraformRouterNat struct {
Name *string `cty:"name"`
Region *string `cty:"region"`
Router *terraformWriter.Literal `cty:"router"`
NATIPAllocateOption *string `cty:"nat_ip_allocate_option"`
SourceSubnetworkIPRangesToNat *string `cty:"source_subnetwork_ip_ranges_to_nat"`
Subnetworks []*terraformRouterNatSubnetwork `cty:"subnetwork"`
}
type terraformRouterNatSubnetwork struct {
Name *terraformWriter.Literal `cty:"name"`
SourceIPRangesToNat []string `cty:"source_ip_ranges_to_nat"`View on GitHub (pinned to 4c8573c808)
Solutions
- Identify the drift: compare the router's actual config (`gcloud compute routers describe`) with the desired kOps spec
- Delete the drifted router (`gcloud compute routers delete`) and re-run `kops update cluster` so it is recreated from spec
- Restore the router to match the kOps model manually if deletion is disruptive
- Pin/align the kOps version used to create the cluster with the one performing updates to avoid model-induced diffs
Example fix
// before: kOps cannot update a drifted router; recreate it out-of-band $ gcloud compute routers delete <router-name> --region <region> $ kops update cluster <cluster> --yes // after: router is recreated matching the model
Defensive patterns
Strategy: validation
Validate before calling
// Compare desired vs actual before apply; recreate if drifted
actual := &gcetasks.Router{}
if err := task.Find(context, actual); err != nil { return err }
if !reflect.DeepEqual(changes, &gcetasks.Router{}) {
fmt.Printf("router %s drifted; delete it before re-running update\n", *task.Name)
} Type guard
func routerNeedsRecreation(changes *gcetasks.Router) bool {
return !reflect.DeepEqual(changes, &gcetasks.Router{})
} Try / catch
if err := applyCluster(); err != nil {
if strings.Contains(err.Error(), "applying changes to Router is unsupported") {
name := extractRouterName(err)
exec("gcloud", "compute", "routers", "delete", name, "--region", region, "--quiet")
return applyCluster() // recreate from spec
}
return err
} Prevention
- Never edit kOps-managed Cloud Routers via gcloud/console
- Use the same kOps version for creation and subsequent updates
- Run `kops update cluster` in dry-run to detect drift before apply
- Track kOps model changes between upgrades and expect router recreation
When it happens
Trigger: An existing GCE router's actual state differs from the desired spec (e.g. someone edited the router manually in the console, or the kOps model changed the NAT config between versions), so changes != &Router{} in the else branch.
Common situations: Manual modifications of the Cloud Router via gcloud/console outside kOps; upgrading kOps to a version that renders different router fields; clusters imported or created with older kOps model revisions.
Related errors
- error creating Router: %w
- error waiting for router creation: %w
- error listing routers: %v
- error deleting router %s: %v
- expected exactly one subnet with GCE IP Aliases
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/20b868fed3c7c2c6.
Report an issue: GitHub.