zhisheng17/flink-learning · error · FlinkException

Could not kill Kubernetes cluster ${clusterId}

Error message

Could not kill Kubernetes cluster ${clusterId}

What it means

Thrown by killCluster when client.stopAndCleanupCluster(clusterId) throws while deleting the cluster's Kubernetes resources. handleException is invoked for richer diagnostics, and the original cause is not attached to the FlinkException, so check the logs/client for the underlying reason.

Source

Thrown at flink-learning-k8s/flink-k8s/src/main/java/org/apache/flink/kubernetes/KubernetesClusterDescriptor.java:268

			return createClusterClientProvider(clusterId);
		} catch (Exception e) {
			try {
				LOG.warn("Failed to create the Kubernetes cluster \"{}\", try to clean up the residual resources.", clusterId);
				client.stopAndCleanupCluster(clusterId);
			} catch (Exception e1) {
				LOG.info("Failed to stop and clean up the Kubernetes cluster \"{}\".", clusterId, e1);
			}
			throw new ClusterDeploymentException("Could not create Kubernetes cluster \"" + clusterId + "\".", e);
		}
	}

	@Override
	public void killCluster(String clusterId) throws FlinkException {
		try {
			client.stopAndCleanupCluster(clusterId);
		} catch (Exception e) {
			client.handleException(e);
			throw new FlinkException("Could not kill Kubernetes cluster " + clusterId);
		}
	}

	@Override
	public void close() {
		try {
			client.close();
		} catch (Exception e) {
			client.handleException(e);
			LOG.error("failed to close client, exception {}", e.toString());
		}
	}
}

View on GitHub (pinned to d731cee761)

Solutions

  1. Check the logged cause (handleException output) for RBAC vs connectivity vs not-found errors.
  2. If resources are already gone, the cluster is effectively killed — verify with kubectl get deploy,svc | grep <clusterId> and ignore the failure.
  3. Grant the service account delete permissions (deployments, services, configmaps, pods) in the namespace.
  4. Retry once the Kubernetes API is reachable if the cause was transient connectivity.
  5. If the namespace is terminating, wait for termination; objects cannot be deleted meanwhile.

Example fix

// before
try {
    descriptor.killCluster(clusterId);
} catch (FlinkException e) {
    throw e; // cause lost
}
// after
descriptor.killCluster(clusterId); // then verify cleanup
kubectl get all -l app=<clusterId>  # confirm nothing residual remains
Defensive patterns

Strategy: try-catch

Validate before calling

boolean stillThere = kubeClient.getService(KubernetesService.ServiceType.REST_SERVICE, clusterId).isPresent();
if (!stillThere) { return; /* nothing to kill */ }

Try / catch

try {
    descriptor.killCluster(clusterId);
} catch (FlinkException e) {
    LOG.warn("Kill failed for {}", clusterId, e); // check RBAC vs already-deleted
}

Prevention

When it happens

Trigger: Calling killCluster(clusterId) when Kubernetes API delete calls fail — RBAC denial on delete, API server unreachable, or resources already gone/deleted concurrently.

Common situations: Deleting a cluster that was already removed; a service account lacking delete permissions on deployments/services/configmaps; network partition to the Kubernetes API; namespace already terminating (deletes rejected).

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


AI-assisted analysis of zhisheng17/flink-learning@d731cee761 (2026-09-06). Data as JSON: /api/errors/5681ebbcfcff7763. Report an issue: GitHub.