apache/shenyu · warning · ShenyuException
doHeartbeat Failed to execute,wait to retry.
Error message
doHeartbeat Failed to execute,wait to retry.
What it means
doHeartbeat() throws ShenyuException when no SelectorDO exists for selectorName + pluginName + namespaceId, meaning a heartbeat arrived for a selector the admin does not know. Like doRegisterURI, the 'wait to retry' wording indicates an expected eventual-consistency race: heartbeats are usually retried by the client until the selector appears.
Solutions
- Let the client retry — Shenyu client registration retries heartbeats until the selector exists.
- Ensure metadata registration (selector creation) succeeds before/independent of heartbeat scheduling.
- Recreate the selector in the dashboard if it was deleted intentionally while the service is still up.
- Check namespaceId consistency between the client config and the selector's namespace.
Defensive patterns
Strategy: retry
Validate before calling
SelectorDO selector = selectorService.findByNameAndPluginNameAndNamespaceId(selectorName, pluginName, namespaceId);
if (selector == null) {
// delay heartbeat until metadata registration has created the selector
return;
} Try / catch
try {
registerService.doHeartbeat(selectorName, uriList, namespaceId);
} catch (ShenyuException e) {
if (e.getMessage().contains("doHeartbeat Failed")) {
scheduler.schedule(() -> doHeartbeatWithRetry(selectorName, uriList, namespaceId), 5, SECONDS);
} else { throw e; }
} Prevention
- Schedule heartbeats only after the initial registration reports success.
- Use exponential backoff for heartbeat retries so logs aren't flooded during startup races.
- Keep namespaceId consistent across metadata and heartbeat calls.
- Recreate or re-register selectors if deleted while backend instances are live.
When it happens
Trigger: Client sends periodic heartbeats for a selectorName that is absent in the DB for that namespace/plugin — heartbeat scheduled before the initial metadata/selector registration completed, or selector deleted in the dashboard while the client is still running.
Common situations: Client restarted before admin registered its metadata; heartbeat timer faster than registration; namespaceId mismatch; an operator removed the selector but left the backend service running and heartbeating.
Understand the failure class
Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.
Related errors
- doRegister Failed to execute, because selectorDO object is…
- Request timeout, the maximum number of retry times has been…
- Retry limit exceeded
- accessToken is null
AI-assisted analysis of apache/shenyu@567142e072 (2026-09-12).
Data as JSON: /api/errors/f8f7ee7ff272a0e2.
Report an issue: GitHub.
Appendix: source
Thrown at shenyu-admin/src/main/java/org/apache/shenyu/admin/service/register/AbstractShenyuClientRegisterServiceImpl.java:247
PluginDO pluginDO = pluginMapper.selectByName(pluginName);
if (Objects.isNull(pluginDO)) {
throw new IllegalArgumentException(errorMsg);
}
NamespacePluginVO namespacePluginRelation = namespacePluginRelMapper.selectByPluginIdAndNamespaceId(pluginDO.getId(), namespaceId);
if (Objects.isNull(namespacePluginRelation)) {
throw new IllegalArgumentException(errorMsg);
}
}
@Override
public String doHeartbeat(final String selectorName, final List<URIRegisterDTO> uriList, final String namespaceId) {
if (CollectionUtils.isEmpty(uriList)) {
return "";
}
String pluginName = PluginNameAdapter.rpcTypeAdapter(rpcType());
SelectorDO selectorDO = selectorService.findByNameAndPluginNameAndNamespaceId(selectorName, pluginName, namespaceId);
if (Objects.isNull(selectorDO)) {
throw new ShenyuException("doHeartbeat Failed to execute,wait to retry.");
}
// update upstream
List<URIRegisterDTO> validUriList = uriList.stream().filter(dto -> Objects.nonNull(dto.getPort()) && StringUtils.isNotBlank(dto.getHost())).toList();
if (CollectionUtils.isEmpty(validUriList)) {
return null;
}
// discovery publish change event.
String selectorId = selectorDO.getId();
// change live node status to TRUE
validUriList.forEach(uriRegisterDTO -> {
DiscoveryUpstreamDTO discoveryUpstreamDTO = CommonUpstreamUtils.buildDefaultDiscoveryUpstreamDTO(uriRegisterDTO.getHost(),
uriRegisterDTO.getPort(),
uriRegisterDTO.getProtocol(),
uriRegisterDTO.getNamespaceId());
try {
// publish instance info event
InstanceInfoReportEvent instanceInfoReportEvent = new InstanceInfoReportEvent(View on GitHub (pinned to 567142e072)