apache/shenyu · error · ShenyuException
The configuration shenyu.discovery.type in xml/yml cannot…
Error message
The configuration shenyu.discovery.type in xml/yml cannot be null
What it means
ClientDiscoveryConfigRefreshedEventListener builds the discovery registration DTO from the `shenyu.discovery.*` client config. When building, it validates that shenyu.discovery.type is non-empty because the discovery SPI implementation is chosen by type; a blank type means no discovery implementation can be selected, so a ShenyuException is thrown and client registration aborts.
Solutions
- Add the discovery type to your client config, e.g. `shenyu: discovery: type: zookeeper` (or nacos/etcd/consul), matching a ShenyuDiscoveryService SPI implementation on the classpath.
- Verify the property is not overridden to empty by an active Spring profile or environment variable.
- Check startup logs for the paired error `shenyu.discovery.serverList ... cannot be null` and fill serverList too, then set type.
- Confirm the corresponding discovery client dependency/starter is present so the chosen type has an implementation.
Example fix
# before
shenyu:
discovery:
serverList: localhost:2181
# after
shenyu:
discovery:
type: zookeeper
serverList: localhost:2181 Defensive patterns
Strategy: validation
Validate before calling
// Spring boot startup check
@PostConstruct
void checkDiscoveryConfig() {
ShenyuClientConfig.DiscoveryConfig d = shenyuClientConfig.getDiscovery();
if (d == null || d.getType() == null || d.getType().isEmpty()) {
throw new IllegalStateException("shenyu.discovery.type must be set (e.g. zookeeper, nacos)");
}
if (d.getServerList() == null || d.getServerList().isEmpty()) {
throw new IllegalStateException("shenyu.discovery.serverList must be set");
}
} Type guard
boolean hasText(String s) { return s != null && !s.trim().isEmpty(); } Prevention
- Always set both shenyu.discovery.type and shenyu.discovery.serverList together when enabling discovery.
- Check active profiles/env vars don't blank the discovery properties.
- Pin config in a shared yml template used across services.
When it happens
Trigger: A Shenyu client app (spring-mvc/spring-cloud etc.) enables service discovery but its yml/properties omits `shenyu.discovery.type` or sets it to an empty string; the listener fires on a config-refresh/ApplicationReady event and calls buildDiscoveryConfigRegisterDTO, which throws immediately after the serverList check passes.
Common situations: Copy-pasted client config that includes serverList but forgot the type field; renaming config keys across versions (e.g. migrating from `shenyu.register` props to `shenyu.discovery`); using a profile that overrides shenyu.discovery and drops type.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- can not find port automatically !
- tars client must config the contextPath, ipAndPort
- dynamic: result.getMessage() from…
- namespaceId is not exist
- before start ProxySelector you need init DiscoveryId=
AI-assisted analysis of apache/shenyu@567142e072 (2026-09-12).
Data as JSON: /api/errors/29ff270bbd6ede22.
Report an issue: GitHub.
Appendix: source
Thrown at shenyu-client/shenyu-client-core/src/main/java/org/apache/shenyu/client/core/register/ClientDiscoveryConfigRefreshedEventListener.java:88
@Override
public void onApplicationEvent(final ContextRefreshedEvent event) {
List<String> namespaceIds = this.getNamespace();
namespaceIds.forEach(namespaceId -> {
DiscoveryConfigRegisterDTO discoveryConfigRegisterDTO = buildDiscoveryConfigRegisterDTO(shenyuDiscoveryConfig, namespaceId);
httpClientRegisterRepository.doPersistDiscoveryConfig(discoveryConfigRegisterDTO);
});
}
protected DiscoveryConfigRegisterDTO buildDiscoveryConfigRegisterDTO(final ShenyuDiscoveryConfig shenyuDiscoveryConfig, final String namespaceId) {
if (StringUtils.isEmpty(shenyuDiscoveryConfig.getServerList())) {
LOG.error("If using service discovery. The configuration shenyu.discovery.name in xml/yml cannot be null");
throw new ShenyuException("The configuration shenyu.discovery.serverList in xml/yml cannot be null");
}
if (StringUtils.isEmpty(shenyuDiscoveryConfig.getType())) {
LOG.error("If using service discovery. The configuration shenyu.discovery.name in xml/yml cannot be null");
throw new ShenyuException("The configuration shenyu.discovery.type in xml/yml cannot be null");
}
return DiscoveryConfigRegisterDTO.builder()
.name(discoveryName())
.selectorName(clientRegisterConfig.getContextPath())
.handler("{}")
.listenerNode(shenyuDiscoveryConfig.getRegisterPath())
.serverList(shenyuDiscoveryConfig.getServerList())
.props(shenyuDiscoveryConfig.getProps())
.discoveryType(shenyuDiscoveryConfig.getType())
.pluginName(plugin.getName())
.namespaceId(namespaceId)
.build();
}
private String discoveryName() {
return "default_" + shenyuDiscoveryConfig.getType();
}
View on GitHub (pinned to 567142e072)