theonedev/onedev · error · ExplicitException

Failed to create ${kind} '${name}': resource still exists af

Error message

Failed to create ${kind} '${name}': resource still exists after deletion

What it means

When creating a Kubernetes resource via kubectl, if the initial create fails because the resource already exists, the code deletes it and retries creation via tryCreateResource. If the retry still returns null (resource still present), it means the delete didn't take effect (e.g. finalizers blocking deletion) and this ExplicitException is thrown.

Source

Thrown at server-core/src/main/java/io/onedev/server/util/KubernetesUtils.java:690

			String kind = ((String) resourceDef.get("kind")).toLowerCase();
			String name = (String) metadata.get("name");
			String namespace = (String) metadata.get("namespace");

			deleteResource(kubectlFactory, kind, name, namespace, true, taskLogger);

			if (kind.equals("pod") && namespace != null) {
				while (resourceExists(kubectlFactory, kind, name, namespace, taskLogger)) {
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						throw new RuntimeException(e);
					}
				}
			}

			String retryResourceName = tryCreateResource(kubectlFactory, file, taskLogger);
			if (retryResourceName == null)
				throw new ExplicitException("Failed to create " + kind + " '" + name + "': resource still exists after deletion");
			return retryResourceName;
		} finally {
			if (file != null)
				file.delete();
		}
	}

	@Nullable
	private static String tryCreateResource(Supplier<Commandline> kubectlFactory, File yamlFile,
			TaskLogger taskLogger) {
		AtomicBoolean alreadyExists = new AtomicBoolean(false);
		AtomicReference<String> resourceNameRef = new AtomicReference<>(null);
		Commandline kubectl = kubectlFactory.get();
		kubectl.addArgs("create", "-f", yamlFile.getAbsolutePath(), "-o", "jsonpath={.metadata.name}");
		var result = kubectl.execute(new LineConsumer() {

			@Override
			public void consume(String line) {

View on GitHub (pinned to d44925c47c)

Solutions

  1. kubectl get <kind> <name> -o yaml to check for finalizers and Terminating state
  2. Remove blocking finalizers (kubectl patch <kind> <name> -p '{"metadata":{"finalizers":[]}}' --type=merge) or delete the stale object manually
  3. Ensure each build uses unique resource names (project/instance prefixes) to avoid collisions
  4. Check RBAC: the service account may lack delete permission so deletion never succeeded

Example fix

// before
throw new ExplicitException("Failed to create " + kind + " '" + name + "': resource still exists after deletion");
// after
// operator-side fix: verify deletion actually completes before retrying
kubectl delete <kind> <name> --wait=true --timeout=60s
kubectl patch <kind> <name> -p '{"metadata":{"finalizers":[]}}' --type=merge   # only if stuck in Terminating
Defensive patterns

Strategy: validation

Validate before calling

kubectl get <kind> <name> -o jsonpath='{.metadata.deletionTimestamp}'  # empty means not deleting; check finalizers too

Try / catch

try {
    KubernetesUtils.createResource(...);
} catch (ExplicitException e) {
    if (e.getMessage().contains("still exists after deletion")) {
        // manually remove finalizers / stale object, then retry
    }
}

Prevention

When it happens

Trigger: Calling KubernetesUtils resource-create helpers when a same-named resource (pod/service/secret etc.) already exists, and after deleting it and retrying the create, tryCreateResource still cannot create it — typically because the old object is stuck in Terminating state with finalizers or the delete failed silently.

Common situations: Leftover resources from a crashed previous build; PVCs or namespaces with kubernetes.io finalizers stuck in Terminating; stale resources from an aborted pipeline; name collisions between concurrent jobs.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06). Data as JSON: /api/errors/018da3a99b4c2b85. Report an issue: GitHub.