tailscale/tailscale · error

error creating Tailscale Service: %w

Error message

error creating Tailscale Service: %w

What it means

Thrown by HAIngressReconciler.maybeProvision when tsClient.VIPServices().CreateOrUpdate fails to create or update the Tailscale Service (VIPService) named svc:<hostname> on the control plane. It can also wrap upstream refusals from owner handling: an existing VIPService without the tailscale.com/owner-references annotation (likely created outside the operator) is rejected rather than adopted, as is one already owned by another resource. Tailscale Services are an alpha tailnet feature, so a tailnet without it enabled also fails here.

Source

Thrown at cmd/k8s-operator/ingress-for-pg.go:363

		Name:        serviceName.String(),
		Tags:        tags,
		Ports:       tsSvcPorts,
		Comment:     managedTSServiceComment,
		Annotations: updatedAnnotations,
	}
	if existingTSSvc != nil {
		tsSvc.Addrs = existingTSSvc.Addrs
	}
	// TODO(irbekrm): right now if two Ingress resources attempt to apply different Tailscale Service configs (different
	// tags, or HTTP endpoint settings) we can end up reconciling those in a loop. We should detect when an Ingress
	// with the same generation number has been reconciled ~more than N times and stop attempting to apply updates.
	if existingTSSvc == nil ||
		!reflect.DeepEqual(tsSvc.Tags, existingTSSvc.Tags) ||
		!reflect.DeepEqual(tsSvc.Ports, existingTSSvc.Ports) ||
		!ownersAreSetAndEqual(tsSvc, *existingTSSvc) {
		logger.Infof("Ensuring Tailscale Service exists and is up to date")
		if err := tsClient.VIPServices().CreateOrUpdate(ctx, tsSvc); err != nil {
			return false, fmt.Errorf("error creating Tailscale Service: %w", err)
		}
	}

	// 5. Update tailscaled's AdvertiseServices config, which should add the Tailscale Service
	// IPs to the ProxyGroup Pods' AllowedIPs in the next netmap update if approved.
	mode := serviceAdvertisementHTTPS
	if isHTTPEndpointEnabled(ing) || isHTTPRedirectEnabled(ing) {
		mode = serviceAdvertisementHTTPAndHTTPS
	}
	if err = r.maybeUpdateAdvertiseServicesConfig(ctx, serviceName, mode, pg); err != nil {
		return false, fmt.Errorf("failed to update tailscaled config: %w", err)
	}

	// 6. Update Ingress status if ProxyGroup Pods are ready.
	count, err := numberPodsAdvertising(ctx, r.Client, r.tsNamespace, pg.Name, serviceName.String())
	if err != nil {
		return false, fmt.Errorf("failed to check if any Pods are configured: %w", err)
	}

View on GitHub (pinned to cfe32b8be6)

Solutions

  1. Read the wrapped message: feature-not-enabled means enable Tailscale Services for the tailnet; ACL/tag errors mean update the tailnet policy so the operator can create VIPServices with those tags.
  2. Check for a foreign VIPService named svc:<hostname> (admin console or API); if it predates the operator, rename the Ingress hostname or delete the VIPService.
  3. Verify the operator's control-plane credentials are valid and egress to the control plane is allowed.
  4. Transient 5xx/network failures resolve via reconcile backoff; check kubectl events on the Ingress for the outcome.
Defensive patterns

Strategy: validation

Validate before calling

// before exposing, ensure the VIPService name is free or operator-owned
name := "svc:" + hostname
if svc, err := tsClient.VIPServices().Get(ctx, name); err == nil {
	if svc.Annotations["tailscale.com/owner-references"] == "" {
		return fmt.Errorf("%s exists but is not operator-owned; delete it or rename the Ingress", name)
	}
}

Type guard

func isPolicyErr(err error) bool { // permanent: do not hot-retry
	return err != nil && (strings.Contains(err.Error(), "not permitted") ||
		strings.Contains(err.Error(), "feature") ||
		strings.Contains(err.Error(), "owner annotation"))
}

Try / catch

if err := tsClient.VIPServices().CreateOrUpdate(ctx, tsSvc); err != nil {
	if isPolicyErr(err) {
		r.recorder.Event(ing, corev1.EventTypeWarning, "VIPServiceRejected", err.Error())
		return false, nil // surface to the user; stop error-looping
	}
	return false, fmt.Errorf("error creating Tailscale Service: %w", err) // transient: backoff requeue
}

Prevention

When it happens

Trigger: Tailscale Services (VIPServices) alpha feature not enabled on the tailnet; the operator device lacks ACL permission to create VIPServices or assign the tags requested via the tailscale.com/tags annotation; control plane 5xx or network failure; an existing svc:<hostname> VIPService created by hand without/with foreign owner annotations; invalid tags or description rejected by the API.

Common situations: Tailnet policy not updated before adopting ProxyGroup Ingresses; operator API credentials expired or revoked; Ingress hostname collides with a manually created VIPService; annotation tags not granted to the operator device.

Related errors


AI-assisted analysis of tailscale/tailscale@cfe32b8be6 (2026-08-15). Data as JSON: /api/errors/dfb04cbfc8877bfd. Report an issue: GitHub.