apache/shenyu · error · ShenyuException

shenyu this discovery has discoveryHandler can't be delete

Error message

shenyu this discovery has discoveryHandler can't be delete

What it means

DiscoveryServiceImpl.delete() refuses to delete a discovery config that still has discovery handler rows attached: if discoveryHandlerMapper.selectByDiscoveryId() returns rows, it throws ShenyuException "shenyu this discovery has discoveryHandler can't be delete". Handlers (proxy selector bindings) reference the discovery, so deleting it would leave dangling bindings; the handlers must be removed first.

Solutions

  1. Delete the discovery handlers referencing this discovery first (via the dashboard or the discovery-handler delete API), then retry the discovery delete.
  2. Identify dependent selectors/proxy bindings and remove or re-point them before deleting.
  3. If the handlers are orphaned, clean up the discovery_handler rows in the DB, then retry.

Example fix

// before
DELETE /discovery/{discoveryId}?namespaceId=ns1  // throws: has discoveryHandler
// after
DELETE /discovery/handler/{handlerId}?namespaceId=ns1  // remove handlers first
DELETE /discovery/{discoveryId}?namespaceId=ns1  // now succeeds
Defensive patterns

Strategy: try-catch

Validate before calling

// before deleting, check for dependent handlers
List<DiscoveryHandlerDO> handlers = discoveryHandlerMapper.selectByDiscoveryId(discoveryId);
if (CollectionUtils.isNotEmpty(handlers)) {
    handlers.forEach(h -> discoveryHandlerService.delete(h.getId(), namespaceId));
}
discoveryService.delete(discoveryId, namespaceId);

Try / catch

try {
    discoveryService.delete(discoveryId, namespaceId);
} catch (ShenyuException e) {
    if (e.getMessage().contains("discoveryHandler can't be delete")) {
        // delete bound discovery handlers first, then retry
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling DELETE /discovery/{id} (with a matching namespaceId) while the discovery still has discovery handlers bound via bindingDiscovery or dashboard-created handler records; cascading cleanup that removes discoveries before handlers.

Common situations: Users deleting a discovery from the dashboard while a proxy selector still points at it; scripts cleaning up config in the wrong order; stale handlers left behind after a selector was removed out-of-band.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of apache/shenyu@567142e072 (2026-09-12). Data as JSON: /api/errors/7bfcfa6653999b47. Report an issue: GitHub.

Appendix: source

Thrown at shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/DiscoveryServiceImpl.java:196

                    .id(UUIDUtils.getInstance().generateShortUuid())
                    .discoveryHandlerId(discoveryHandlerDO.getId())
                    .selectorId(selectorDO.getId())
                    .pluginName(discoveryConfigRegisterDTO.getPluginName()).build();
            discoveryRelMapper.insertSelective(discoveryRefDO);
            discoveryHandlerMapper.insertSelective(discoveryHandlerDO);
        }
        DiscoveryProcessor discoveryProcessor = discoveryProcessorHolder.chooseProcessor(discoveryConfigRegisterDTO.getDiscoveryType());
        discoveryProcessor.createDiscovery(discoveryDO);
        discoveryProcessor.createProxySelector(DiscoveryTransfer.INSTANCE.mapToDTO(discoveryHandlerDO), proxySelectorDTO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String delete(final String discoveryId, final String namespaceId) {
        List<DiscoveryHandlerDO> discoveryHandlerDOS = discoveryHandlerMapper.selectByDiscoveryId(discoveryId);
        if (CollectionUtils.isNotEmpty(discoveryHandlerDOS)) {
            LOG.warn("shenyu this discovery has discoveryHandler can't be delete");
            throw new ShenyuException("shenyu this discovery has discoveryHandler can't be delete");
        }
        DiscoveryDO discoveryDO = discoveryMapper.selectById(discoveryId);
        if (Objects.isNull(discoveryDO) || !Objects.equals(discoveryDO.getNamespaceId(), namespaceId)) {
            LOG.warn("shenyu discovery {} is not found in namespace {}", discoveryId, namespaceId);
            throw new ShenyuException("shenyu this discovery is not found in current namespace");
        }
        DiscoveryProcessor discoveryProcessor = discoveryProcessorHolder.chooseProcessor(discoveryDO.getDiscoveryType());
        discoveryProcessor.removeDiscovery(discoveryDO);
        discoveryMapper.delete(discoveryId, namespaceId);
        return ShenyuResultMessage.DELETE_SUCCESS;
    }

    private DiscoveryVO create(final DiscoveryDTO discoveryDTO) {
        if (Objects.isNull(discoveryDTO)) {
            return null;
        }
        Timestamp currentTime = new Timestamp(System.currentTimeMillis());
        DiscoveryDO discoveryDO = DiscoveryDO.builder()

View on GitHub (pinned to 567142e072)