{"record":{"id":"a6921f6916b45019","repo":"helm/helm","slug":"object-not-found-skipping-delete-w","errorCode":null,"errorMessage":"object not found, skipping delete: %w","messagePattern":"object not found, skipping delete: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"pkg/kube/client.go","lineNumber":941,"sourceCode":"\t\t\t\t\tslog.String(\"namespace\", target.Namespace),\n\t\t\t\t\tslog.String(\"name\", target.Name),\n\t\t\t\t\tslog.String(\"kind\", target.Mapping.GroupVersionKind.Kind),\n\t\t\t\t\tslog.Any(\"error\", err))\n\t\t\t}\n\t\t\tmtx.Lock()\n\t\t\tdefer mtx.Unlock()\n\t\t\tres.Deleted = append(res.Deleted, target)\n\t\t\treturn nil\n\t\t}\n\t\tmtx.Lock()\n\t\tdefer mtx.Unlock()\n\t\t// Collect the error and continue on\n\t\terrs = append(errs, err)\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\tif errors.Is(err, ErrNoObjectsVisited) {\n\t\t\terr = fmt.Errorf(\"object not found, skipping delete: %w\", err)\n\t\t}\n\t\terrs = append(errs, err)\n\t}\n\tif errs != nil {\n\t\treturn nil, errs\n\t}\n\treturn res, nil\n}\n\n// https://github.com/kubernetes/kubectl/blob/197123726db24c61aa0f78d1f0ba6e91a2ec2f35/pkg/cmd/apply/apply.go#L439\nfunc isIncompatibleServerError(err error) bool {\n\t// 415: Unsupported media type means we're talking to a server which doesn't\n\t// support server-side apply.\n\tvar sErr *apierrors.StatusError\n\tif !errors.As(err, &sErr) {\n\t\t// Non-StatusError means the error isn't because the server is incompatible.\n\t\treturn false\n\t}","sourceCodeStart":923,"sourceCodeEnd":959,"githubUrl":"https://github.com/helm/helm/blob/2a29f1770b62844b27197d2507377361d45ad7c0/pkg/kube/client.go#L923-L959","documentation":"Client.Delete visits each resource and deletes it, treating NotFound as success. If perform reports ErrNoObjectsVisited (\"no objects visited\") — the resource list was empty or nothing was visitable — that sentinel is wrapped as \"object not found, skipping delete\" and returned among the errors. Deletion was skipped simply because there was nothing to delete.","triggerScenarios":"Uninstall/delete invoked with an empty or fully-filtered ResourceList: the release's resources were already deleted manually, the chart rendered to zero manifests, or the object list was constructed incorrectly upstream.","commonSituations":"Double uninstall (second run finds nothing); resources removed out-of-band before helm uninstall; SDK code passing a ResourceList built from an empty render.","solutions":["If the resources are indeed gone, treat this as success — verify with kubectl that nothing remains, then continue cleanup","If resources should still exist, find out why the list was empty (check the release storage / rendered manifests) before retrying","Avoid double-deletion flows: guard uninstall automation against re-entry"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if len(resources) == 0 {\n\t// nothing to delete: skip the call entirely\n\treturn &kube.Result{}, nil\n}\nres, errs := c.Delete(resources, metav1.DeletePropagationBackground)","typeGuard":null,"tryCatchPattern":"res, errs := c.Delete(resources, policy)\nfiltered := errs[:0]\nfor _, err := range errs {\n\tif errors.Is(err, kube.ErrNoObjectsVisited) {\n\t\tcontinue // nothing matched; treat as no-op success\n\t}\n\tfiltered = append(filtered, err)\n}\nif len(filtered) > 0 {\n\treturn filtered\n}","preventionTips":["Make uninstall flows idempotent: tolerate already-deleted resources and empty manifests","Check release storage before constructing the delete list so double-uninstall cannot reach Delete"],"tags":["kubernetes","delete","uninstall","idempotency","helm"],"backgroundTag":null,"analyzedSha":"2a29f1770b62844b27197d2507377361d45ad7c0","analyzedAt":"2026-08-15T22:02:47.490Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}