kubernetes/kops · error
error reading Keyset %q: %v
Error message
error reading Keyset %q: %v
What it means
This error is returned by ClientsetSecretStore.DeleteSecret when the Get call for the Keyset fails with an error other than NotFound (NotFound is deliberately treated as success). It wraps the underlying client-go error, so the cause (forbidden, timeout, connection refused) is in the %v text. It means the delete could not even verify the keyset's existence or read its type before deleting.
Source
Thrown at upup/pkg/fi/secrets/clientset_secretstore.go:158
}
if s == nil {
return nil, fmt.Errorf("Secret not found: %q", name)
}
return s, nil
}
// DeleteSecret implements fi.SecretStore::DeleteSecret
func (c *ClientsetSecretStore) DeleteSecret(name string) error {
ctx := context.TODO()
client := c.clientset.Keysets(c.namespace)
keyset, err := client.Get(ctx, name, metav1.GetOptions{})
if err != nil {
if errors.IsNotFound(err) {
return nil
}
return fmt.Errorf("error reading Keyset %q: %v", name, err)
}
if keyset.Spec.Type != kops.SecretTypeSecret {
return fmt.Errorf("mismatch on Keyset type on %q", name)
}
if err := client.Delete(ctx, name, metav1.DeleteOptions{}); err != nil {
return fmt.Errorf("error deleting Keyset %q: %v", name, err)
}
return nil
}
// GetOrCreateSecret implements fi.SecretStore::GetOrCreateSecret
func (c *ClientsetSecretStore) GetOrCreateSecret(ctx context.Context, name string, secret *fi.Secret) (*fi.Secret, bool, error) {
for i := 0; i < 2; i++ {
s, err := c.FindSecret(name)
if err != nil {View on GitHub (pinned to 4c8573c808)
Solutions
- Read the wrapped error to identify the root cause (forbidden vs timeout vs connection)
- Verify RBAC allows get (and delete) on keysets in the target namespace
- Check API server reachability: kubectl get keysets -n <namespace> <name>
- Retry after connectivity is restored — deletion is safe to re-run because NotFound is treated as success
- Confirm the correct cluster/namespace before retrying
Example fix
// before: single attempt fails on transient errors
if err := store.DeleteSecret("admin"); err != nil { return err }
// after: retry transient failures; NotFound is already a no-op
var lastErr error
for i := 0; i < 3; i++ {
err := store.DeleteSecret("admin")
if err == nil { return nil }
lastErr = err
if strings.Contains(err.Error(), "forbidden") { return err }
time.Sleep(time.Duration(i+1) * time.Second)
}
return lastErr Defensive patterns
Strategy: try-catch
Validate before calling
// preflight: confirm get access on the keyset before deleting
client := clientset.Keysets(namespace)
if _, err := client.Get(context.TODO(), NamePrefix+name, metav1.GetOptions{}); err != nil {
if errors.IsNotFound(err) { return nil } // already gone
return fmt.Errorf("preflight get failed: %v", err)
} Type guard
func isTransientAPIError(err error) bool {
return err != nil && !errors.IsNotFound(err) && !errors.IsForbidden(err)
} Try / catch
err := store.DeleteSecret(name)
if err != nil && strings.Contains(err.Error(), "error reading Keyset") {
for i := 0; i < 3; i++ {
time.Sleep(time.Duration(1<<i) * time.Second)
if err = store.DeleteSecret(name); err == nil { break }
}
}
if err != nil { return err } Prevention
- Ensure the identity has get+delete RBAC on keysets before running deletes
- Treat DeleteSecret as idempotent — NotFound already returns nil, so safe retries are fine
- Check API server connectivity before bulk delete operations
- Confirm the target namespace/cluster to avoid cross-cluster API errors
When it happens
Trigger: DeleteSecret(name) calls client.Get(ctx, name, metav1.GetOptions{}); the API server returns a non-NotFound error — RBAC denial on keysets/get, API server unreachable, request timeout, or invalid name rejected by validation.
Common situations: Running `kops delete secret` with a ServiceAccount lacking get permission on keysets; API server temporarily down; wrong namespace configured; network/VPN interruption during automation.
Understand the failure class
Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.
Related errors
- error listing machines: %w
- error listing nodes: %v
- error listing Pods: %v
- error deleting SSHCredential: %v
- error adding needs-update label: %v
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/609585bdd67cff37.
Report an issue: GitHub.