istio/istio · error

no %q data found

Error message

no %q data found

What it means

The sentinel errMissingRootCAKey in istioctl/pkg/multicluster/remote_secret.go: the token secret passed to createRemoteSecretFromPlugin does not contain the 'ca.crt' key (v1.ServiceAccountRootCAKey). It is thrown by tokenDataFromSecret when the secret exists but its Data map lacks the root CA entry.

Source

Thrown at istioctl/pkg/multicluster/remote_secret.go:216

	authProviderConfig *api.AuthProviderConfig,
) (*v1.Secret, error) {
	caData, ok := tokenSecret.Data[v1.ServiceAccountRootCAKey]
	if !ok {
		return nil, errMissingRootCAKey
	}

	// Create a Kubeconfig to access the remote cluster using the auth provider plugin.
	kubeconfig := createPluginKubeconfig(caData, clusterName, server, tlsServerName, authProviderConfig)
	if err := clientcmd.Validate(*kubeconfig); err != nil {
		return nil, fmt.Errorf("invalid kubeconfig: %v", err)
	}

	// Encode the Kubeconfig in a secret that can be loaded by Istio to dynamically discover and access the remote cluster.
	return createRemoteServiceAccountSecret(kubeconfig, clusterName, secName)
}

var (
	errMissingRootCAKey = fmt.Errorf("no %q data found", v1.ServiceAccountRootCAKey)
	errMissingTokenKey  = fmt.Errorf("no %q data found", v1.ServiceAccountTokenKey)
)

func createRemoteSecretFromTokenAndServer(
	client kube.CLIClient, tokenSecret *v1.Secret, clusterName, server, tlsServerName, secName string,
) (*v1.Secret, error) {
	caData, token, err := waitForTokenData(client, tokenSecret)
	if err != nil {
		return nil, err
	}

	// Create a Kubeconfig to access the remote cluster using the remote service account credentials.
	kubeconfig := createBearerTokenKubeconfig(caData, token, clusterName, server, tlsServerName)
	if err := clientcmd.Validate(*kubeconfig); err != nil {
		return nil, fmt.Errorf("invalid kubeconfig: %v", err)
	}

	// Encode the Kubeconfig in a secret that can be loaded by Istio to dynamically discover and access the remote cluster.

View on GitHub (pinned to 8dc789c5cf)

Solutions

  1. Inspect the secret: `kubectl get secret <name> -o jsonpath='{.data}'` — confirm ca.crt exists.
  2. If keys are missing, delete the manually created token secret and let the tool recreate it, then retry.
  3. On k8s >= 1.24, create a projected token via `kubectl create token` or a TokenRequest, or use a secret manifest of type kubernetes.io/service-account-token with the kubernetes.io/service-account.name annotation.
  4. Point --secret-name at a genuine service-account-token secret.

Example fix

# before: secret exists but is opaque
type: Opaque

# after: properly typed SA token secret the tool can read
apiVersion: v1
kind: Secret
metadata:
  name: istio-reader-istio-remote-secret-token
  annotations:
    kubernetes.io/service-account.name: istio-reader
type: kubernetes.io/service-account-token
Defensive patterns

Strategy: validation

Validate before calling

// Check the required keys before handing the secret to the plugin path
func hasRootCA(secret *corev1.Secret) bool {
    d, ok := secret.Data[corev1.ServiceAccountRootCAKey]
    return ok && len(d) > 0
}
if !hasRootCA(tokenSecret) {
    return nil, fmt.Errorf("secret %s lacks %s; wait for token controller or use a projected token",
        tokenSecret.Name, corev1.ServiceAccountRootCAKey)
}

Type guard

func isMissingRootCA(err error) bool {
    return err != nil && strings.Contains(err.Error(),
        fmt.Sprintf("no %q data found", corev1.ServiceAccountRootCAKey))
}

Try / catch

caData, err := tokenDataFromSecret(secret)
if err != nil {
    if isMissingRootCA(err) {
        // poll like waitForTokenData does for the bearer path
        time.Sleep(2 * time.Second)
        caData, err = tokenDataFromSecret(secret)
    }
    if err != nil {
        return nil, err
    }
}

Prevention

When it happens

Trigger: The service-account token secret referenced (found by listing, by --secret-name, or just created) has no Data["ca.crt"] — either it is not really a kubernetes.io/service-account-token secret, or the API server has not yet populated the projected keys.

Common situations: Race right after secret creation where kube-controller-manager has not stamped ca.crt/token yet (the code has waitForTokenData for the bearer path but the plugin path reads directly); pointing --secret-name at an opaque/TLS secret; k8s 1.24+ where legacy auto-generated SA secrets no longer exist; secret created from a manifest without the token controller.

Related errors


AI-assisted analysis of istio/istio@8dc789c5cf (2026-08-15). Data as JSON: /api/errors/3dbfdc54c30867dd. Report an issue: GitHub.