cilium/cilium · error
unsupported IPv6 zone in address %s
Error message
unsupported IPv6 zone in address %s
What it means
When validating a stored GlobalService/CMAP entry, every frontend address must parse as a bare netip.Addr. If the address includes an IPv6 zone (e.g. fe80::1%eth0), parsing succeeds but the zone is rejected because zoned addresses are meaningless across clusters. validate returns this error so the entry is rejected before being published.
Source
Thrown at pkg/clustermesh/store/store.go:141
return nil
}
func (s *ClusterService) validate() error {
switch {
case s.Cluster == "":
return errors.New("cluster is unset")
case s.Namespace == "":
return errors.New("namespace is unset")
case s.Name == "":
return errors.New("name is unset")
}
for address := range s.Frontends {
if parsed, err := netip.ParseAddr(address); err != nil {
return err
} else if parsed.Zone() != "" {
return fmt.Errorf("unsupported IPv6 zone in address %s", address)
}
}
for address := range s.Backends {
if parsed, err := netip.ParseAddr(address); err != nil {
return err
} else if parsed.Zone() != "" {
return fmt.Errorf("unsupported IPv6 zone in address %s", address)
}
}
return nil
}
// BackendZone locates the backend to a specific zone and specifies what zones
// the backend should be used in for topology aware routing.
//
// WARNING - STABLE API: Changing the structure or values of this willView on GitHub (pinned to ac7b90affa)
Solutions
- Remove the zone suffix from the frontend address (use fe80::1, not fe80::1%eth0).
- Use a globally-routable IPv6 address or a specific ULA instead of a link-local/zoned address as a frontend.
- Fix the automation/source that generates frontends to strip or reject zone identifiers.
Example fix
// before
frontends: {"fe80::1%eth0": {"80": {"p1": 80}}}
// after
frontends: {"fd00::10": {"80": {"p1": 80}}} Defensive patterns
Strategy: validation
Validate before calling
addr, err := netip.ParseAddr(frontend)
if err != nil || addr.Zone() != "" {
return fmt.Errorf("frontend %s must be a zone-free IP address", frontend)
} Type guard
func isZoneFreeIP(s string) bool {
a, err := netip.ParseAddr(s)
return err == nil && a.Zone() == ""
} Try / catch
if err := store.Validate(); err != nil {
if strings.Contains(err.Error(), "unsupported IPv6 zone") {
log.WithError(err).Warn("dropping entry with zoned IPv6 address")
return nil // skip entry
}
return err
} Prevention
- Strip zone identifiers before storing any address (netip.ParseAddr then re-serialize).
- Reject link-local addresses as global-service frontends at config-admission time.
- Lint generated configs for '%' in IP fields.
When it happens
Trigger: A CiliumGlobalServiceEndpoint/GlobalService whose Frontends map contains an IPv6 address with a zone suffix (%eth0, %ens1), typically copied from a node-local scoped address.
Common situations: Users copying link-local addresses from ip -6 output into global service configuration; automation exporting zoned addresses from a single node; misconfigured IPv6 frontends on hosts with multiple interfaces.
Related errors
- invalid IPv6 endpoint address: %s
- cluster is unset
- namespace is unset
- name is unset
- exportCreationTimestamp is unset
AI-assisted analysis of cilium/cilium@ac7b90affa (2026-08-31).
Data as JSON: /api/errors/c29feb97465bcf35.
Report an issue: GitHub.