Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for Infrastructure as Code By James Joyner IV · · 9 min read

IaC Error Guide: 'rendered manifests contain a resource that already exists' in Helm

Fix the Helm 'rendered manifests contain a resource that already exists' error: repair missing ownership annotations, adopt orphaned objects, and clear failed installs.

  • #iac
  • #troubleshooting
  • #errors
  • #helm

Overview

Helm refuses to create an object that already exists in the cluster unless that object carries the ownership metadata Helm uses to claim it. When you run helm install (or helm upgrade --install), Helm renders the chart, then checks each rendered resource against the live cluster. If a matching object exists but is not owned by the release you are installing, Helm aborts rather than risk overwriting something it did not create.

You will see this on helm install or helm upgrade:

Error: INSTALLATION FAILED: rendered manifests contain a resource that already exists. Unable to continue with install: ConfigMap "myapp-config" in namespace "production" exists and cannot be imported into the current release: invalid ownership metadata; label validation error: missing key "app.kubernetes.io/managed-by": must be set to "Helm"; annotation validation error: missing key "meta.helm.sh/release-name": must be set to "myapp"; annotation validation error: missing key "meta.helm.sh/release-namespace": must be set to "production"

Ownership is tracked by one label and two annotations: app.kubernetes.io/managed-by=Helm, meta.helm.sh/release-name, and meta.helm.sh/release-namespace. If any are missing or point at a different release, Helm treats the object as foreign and stops. The error is namespace-specific and per-resource, so a chart can fail on one ConfigMap while every other object installs cleanly.

Symptoms

  • helm install or helm upgrade --install aborts before creating any resources.
  • The message names a specific kind, name, and namespace that “exists and cannot be imported”.
  • The object is present in the cluster but helm list does not show a release that owns it.
  • A previous helm install failed mid-way and left a few objects behind.
helm install myapp ./chart -n production
Error: INSTALLATION FAILED: rendered manifests contain a resource that already exists. Unable to continue with install: ConfigMap "myapp-config" in namespace "production" exists and cannot be imported into the current release: invalid ownership metadata; label validation error: missing key "app.kubernetes.io/managed-by": must be set to "Helm"
kubectl get configmap myapp-config -n production -o yaml | grep -A3 annotations
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","kind":"ConfigMap",...}
  creationTimestamp: "2026-05-02T09:14:31Z"

(No meta.helm.sh/* annotations — Helm does not own this object.)

Common Root Causes

1. The resource was created outside Helm

Someone applied the object with kubectl apply or another tool, so it has no Helm ownership metadata. Helm sees a live object with the same name and refuses to adopt it.

kubectl get configmap myapp-config -n production \
  -o jsonpath='{.metadata.labels.app\.kubernetes\.io/managed-by}{"\n"}'

(Empty output — no managed-by label, so it was not created by Helm.)

2. Orphaned objects from a failed install

A prior helm install failed partway through. Helm rolled back its release record but left some already-created objects in the cluster. The next install finds those leftovers and aborts.

helm list -A --uninstalling --pending
kubectl get all -n production -l app.kubernetes.io/instance=myapp
NAME    NAMESPACE   REVISION  STATUS  CHART        APP VERSION
NAME      READY   STATUS    RESTARTS   AGE
service/myapp-svc  ClusterIP  10.96.4.12  <none>  80/TCP  6m

(No release listed, but a Service from the failed attempt is still present.)

3. Missing ownership label and annotations

The object has the right name but is missing the app.kubernetes.io/managed-by label or one of the meta.helm.sh annotations. This is the literal cause the error message reports.

kubectl get configmap myapp-config -n production -o yaml \
  | grep -E 'managed-by|meta.helm.sh'

(No matching keys — the trio Helm requires is absent.)

4. Two releases owning the same object

Two charts (or the same chart installed under different release names) both render an object with the same name and namespace. The annotations point at a different release, so the second install cannot claim it.

kubectl get configmap myapp-config -n production -o yaml \
  | grep -A2 'meta.helm.sh'
    meta.helm.sh/release-name: legacy-app
    meta.helm.sh/release-namespace: production

(The object belongs to release legacy-app, not myapp — a naming collision.)

5. Cluster-scoped CRDs and other shared objects

CustomResourceDefinitions, ClusterRoles, and other cluster-scoped objects are global. A second chart that ships the same CRD finds it already installed by another release (or by kubectl create -f crds/) and stops.

kubectl get crd widgets.example.com -o yaml | grep -A3 annotations
  annotations:
    controller-gen.kubebuilder.io/version: v0.14.0
  creationTimestamp: "2026-04-18T11:02:55Z"

(Installed by a controller’s manifests, not Helm — no ownership metadata.)

6. Namespace conflict / pre-created namespace

When the chart templates the Namespace object itself but the namespace was created manually (or by kubectl create ns), the install collides on the Namespace resource.

kubectl get namespace production -o yaml | grep -A3 annotations
  annotations:
    {}
  creationTimestamp: "2026-03-01T08:00:00Z"

(The namespace exists with no Helm metadata, so a chart that renders its own Namespace cannot adopt it.)

Diagnostic Workflow

Step 1: Identify the exact conflicting object

Read the error message — it names the kind, name, and namespace. Confirm the object exists:

kubectl get configmap myapp-config -n production

The kind/name in the error is the single object blocking the install; everything else in the chart is fine.

Step 2: Check whether any release already owns it

kubectl get configmap myapp-config -n production -o yaml \
  | grep -E 'managed-by|meta.helm.sh/release-(name|namespace)'
helm list -A

If the annotations name a different release, you have a collision (cause 4). If they are absent, the object is unmanaged (causes 1, 3, 5, 6).

Step 3: Look for leftovers from a failed install

helm list -A --uninstalling --pending --failed
kubectl get all,configmap,secret -n production -l app.kubernetes.io/instance=myapp

A failed/pending release or stray labelled objects point to cause 2.

Step 4: Decide adopt vs. delete

If you want Helm to take over the existing object, patch the ownership metadata onto it:

kubectl annotate configmap myapp-config -n production \
  meta.helm.sh/release-name=myapp \
  meta.helm.sh/release-namespace=production --overwrite
kubectl label configmap myapp-config -n production \
  app.kubernetes.io/managed-by=Helm --overwrite

If the object is genuinely orphaned junk, delete it instead:

kubectl delete configmap myapp-config -n production

Step 5: Re-run the install and verify ownership

helm upgrade --install myapp ./chart -n production
helm list -n production

Confirm the release shows deployed and the object now carries Helm metadata.

Example Root Cause Analysis

A platform team runs helm install myapp ./chart -n production for a new service and it fails:

Error: INSTALLATION FAILED: rendered manifests contain a resource that already exists. Unable to continue with install: ConfigMap "myapp-config" in namespace "production" exists and cannot be imported into the current release: invalid ownership metadata; annotation validation error: missing key "meta.helm.sh/release-name": must be set to "myapp"

helm list -A shows no release named myapp, so it is not a collision with another chart. Inspecting the object:

kubectl get configmap myapp-config -n production -o yaml | grep -A4 annotations
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","kind":"ConfigMap","metadata":{"name":"myapp-config"}}
  creationTimestamp: "2026-06-19T16:40:12Z"

The last-applied-configuration annotation reveals it was created by kubectl apply during a manual test four days ago — cause 1. The team wants to keep its current data, so they adopt it into the release instead of deleting:

kubectl annotate configmap myapp-config -n production \
  meta.helm.sh/release-name=myapp \
  meta.helm.sh/release-namespace=production --overwrite
kubectl label configmap myapp-config -n production \
  app.kubernetes.io/managed-by=Helm --overwrite
helm upgrade --install myapp ./chart -n production
Release "myapp" does not exist. Installing it now.
NAME: myapp
STATUS: deployed
REVISION: 1

Helm now owns the ConfigMap and the install completes.

Prevention Best Practices

  • Never kubectl apply an object that a Helm chart also templates. Pick one owner per resource and keep it consistent across environments.
  • Run helm upgrade --install instead of helm install so re-running a partially failed deploy reuses the same release record rather than colliding.
  • After a failed install, clean up with helm uninstall <release> (or delete the labelled objects) before retrying, so no orphans remain.
  • Manage CRDs deliberately — install them once via the chart’s crds/ directory or a dedicated release, and keep other charts from re-shipping the same definitions.
  • Keep ownership conventions in version control alongside the rest of your infrastructure as code so adoption commands are reviewed, not improvised.
  • When triaging a failed rollout under time pressure, the free incident assistant can turn a Helm ownership error into the specific adopt-or-delete command for the named object.

Quick Command Reference

# Run install idempotently
helm upgrade --install myapp ./chart -n production

# See what the chart will render (and the object names)
helm template myapp ./chart -n production | grep -E 'kind:|name:'

# Inspect ownership metadata on the conflicting object
kubectl get configmap myapp-config -n production -o yaml | grep -A3 annotations
kubectl get configmap myapp-config -n production -o yaml | grep -E 'managed-by|meta.helm.sh'

# Find failed/pending releases and stray labelled objects
helm list -A --uninstalling --pending --failed
kubectl get all -n production -l app.kubernetes.io/instance=myapp

# Adopt an existing object into the release
kubectl annotate <kind> <name> -n production \
  meta.helm.sh/release-name=myapp meta.helm.sh/release-namespace=production --overwrite
kubectl label <kind> <name> -n production app.kubernetes.io/managed-by=Helm --overwrite

# Or remove the orphan and reinstall
kubectl delete <kind> <name> -n production
helm upgrade --install myapp ./chart -n production

Conclusion

The “rendered manifests contain a resource that already exists” error means a live object lacks the ownership metadata that lets Helm claim it. The usual root causes:

  1. The object was created outside Helm, via kubectl apply or another tool.
  2. Orphaned objects left behind by a helm install that failed mid-way.
  3. The required managed-by label or meta.helm.sh annotations are missing.
  4. Two releases render an object with the same name and namespace.
  5. A shared cluster-scoped object (CRD, ClusterRole) is already installed elsewhere.
  6. A namespace or other resource the chart templates was pre-created manually.

Check whether any release already owns the named object, then choose deliberately: adopt it by patching the label and annotations, or delete the orphan and re-run with helm upgrade --install.

Free download · 368-page PDF

Download the Free 500-Prompt DevOps AI Toolkit

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.