{"record":{"id":"469c0104a4546d90","repo":"alibaba/nacos","slug":"21009","errorCode":"21009","errorMessage":"Service {service.getGroupedServiceName()} is not empty, can't be delete. Please unregister instance first","messagePattern":"Service (.+?) is not empty, can't be delete\\. Please unregister instance first","errorType":"validation","errorClass":"NacosApiException","httpStatus":400,"severity":"error","filePath":"naming/src/main/java/com/alibaba/nacos/naming/core/ServiceOperatorV2Impl.java","lineNumber":134,"sourceCode":"    public void delete(String namespaceId, String serviceName) throws NacosException {\n        Service service = getServiceFromGroupedServiceName(namespaceId, serviceName, true);\n        delete(service);\n    }\n    \n    /**\n     * Delete service.\n     *\n     * @param service service v2\n     * @throws NacosException nacos exception during delete\n     */\n    public void delete(Service service) throws NacosException {\n        if (!ServiceManager.getInstance().containSingleton(service)) {\n            throw new NacosApiException(NacosException.INVALID_PARAM, ErrorCode.SERVICE_NOT_EXIST,\n                String.format(\"service %s not found!\", service.getGroupedServiceName()));\n        }\n        \n        if (!serviceStorage.getPushData(service).getHosts().isEmpty()) {\n            throw new NacosApiException(NacosException.INVALID_PARAM,\n                ErrorCode.SERVICE_DELETE_FAILURE,\n                \"Service \" + service.getGroupedServiceName()\n                    + \" is not empty, can't be delete. Please unregister instance first\");\n        }\n        metadataOperateService.deleteServiceMetadata(service);\n    }\n    \n    @Override\n    public ObjectNode queryService(String namespaceId, String serviceName) throws NacosException {\n        Service service = getServiceFromGroupedServiceName(namespaceId, serviceName, true);\n        if (!ServiceManager.getInstance().containSingleton(service)) {\n            throw new NacosApiException(NacosException.INVALID_PARAM, ErrorCode.SERVICE_NOT_EXIST,\n                \"service not found, namespace: \" + namespaceId + \", serviceName: \" + serviceName);\n        }\n        ObjectNode result = JacksonUtils.createEmptyJsonNode();\n        ServiceMetadata serviceMetadata =\n            metadataManager.getServiceMetadata(service).orElse(new ServiceMetadata());\n        setServiceMetadata(result, serviceMetadata, service);","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/alibaba/nacos/blob/9b989acdf181d00898f2e8839257bb2b2a3cefe3/naming/src/main/java/com/alibaba/nacos/naming/core/ServiceOperatorV2Impl.java#L116-L152","documentation":"Thrown by ServiceOperatorV2Impl.delete(Service) when the service singleton exists but serviceStorage.getPushData(service).getHosts() is non-empty — meaning the service still has registered instances. Error code 21009 (SERVICE_DELETE_FAILURE), NacosException.INVALID_PARAM (400). Nacos refuses to delete a service that still hosts instances to prevent orphaned references.","triggerScenarios":"Calling delete-service while one or more instances are still registered under the service. The instances may be ephemeral (still being heartbeated by clients) or persistent (stored in the CP log). Even unhealthy instances count as long as they are in the host list.","commonSituations":"Decommissioning a service without first deregistering all instances. Clients are still running and re-registering ephemeral instances faster than they can be removed. Persistent instances remain in the Raft log. A stale client keeps the instance alive via heartbeats.","solutions":["Deregister all instances for the service first (DELETE instance API or gRPC deregister), then retry delete.","Stop all client processes that register instances against this service, then wait for ephemeral instances to expire.","For persistent instances, ensure the CP/Raft log entry is removed via the deregister path (not just in-memory).","Verify the host list is empty via selectInstances before calling delete."],"exampleFix":"// before\nserviceOperatorV2.delete(namespaceId, serviceName);\n\n// after — drain instances first\nServiceInfo info = serviceStorage.getData(service);\nfor (Instance h : info.getHosts()) {\n    instanceOperator.deregisterInstance(namespaceId, group, name,\n        h.getIp(), h.getPort(), h.getClusterName());\n}\n// wait for propagation, then\nserviceOperatorV2.delete(namespaceId, serviceName);","handlingStrategy":"validation","validationCode":"ServiceInfo info = serviceStorage.getData(service);\nif (!info.getHosts().isEmpty()) {\n    // drain instances first\n    for (Instance h : info.getHosts()) {\n        instanceOperator.deregisterInstance(namespaceId, group, name,\n            h.getIp(), h.getPort(), h.getClusterName());\n    }\n    // wait for propagation\n}\nserviceOperatorV2.delete(service);","typeGuard":null,"tryCatchPattern":"try {\n    serviceOperatorV2.delete(service);\n} catch (NacosApiException e) {\n    if (e.getErrCode() == NacosException.INVALID_PARAM\n            && ErrorCode.SERVICE_DELETE_FAILURE.getCode() == 21009) {\n        // service still has instances — drain and retry\n    } else throw e;\n}","preventionTips":["Always deregister all instances before deleting a service.","Stop client processes that re-register ephemeral instances before cleanup.","Verify the host list is empty before calling delete."],"tags":["naming","service-delete","not-empty","instances","validation"],"backgroundTag":null,"analyzedSha":"9b989acdf181d00898f2e8839257bb2b2a3cefe3","analyzedAt":"2026-08-14T07:17:31.569Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}