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 will

View on GitHub (pinned to ac7b90affa)

Solutions

  1. Remove the zone suffix from the frontend address (use fe80::1, not fe80::1%eth0).
  2. Use a globally-routable IPv6 address or a specific ULA instead of a link-local/zoned address as a frontend.
  3. 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

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


AI-assisted analysis of cilium/cilium@ac7b90affa (2026-08-31). Data as JSON: /api/errors/c29feb97465bcf35. Report an issue: GitHub.