{"record":{"id":"29ff270bbd6ede22","repo":"apache/shenyu","slug":"the-configuration-shenyu-discovery-type-in-xml-yml-cannot-be","errorCode":null,"errorMessage":"The configuration shenyu.discovery.type in xml/yml cannot be null","messagePattern":"The configuration shenyu\\.discovery\\.type in xml/yml cannot be null","errorType":"exception","errorClass":"ShenyuException","httpStatus":null,"severity":"error","filePath":"shenyu-client/shenyu-client-core/src/main/java/org/apache/shenyu/client/core/register/ClientDiscoveryConfigRefreshedEventListener.java","lineNumber":88,"sourceCode":"\n    @Override\n    public void onApplicationEvent(final ContextRefreshedEvent event) {\n        List<String> namespaceIds = this.getNamespace();\n        namespaceIds.forEach(namespaceId -> {\n            DiscoveryConfigRegisterDTO discoveryConfigRegisterDTO = buildDiscoveryConfigRegisterDTO(shenyuDiscoveryConfig, namespaceId);\n            httpClientRegisterRepository.doPersistDiscoveryConfig(discoveryConfigRegisterDTO);\n        });\n\n    }\n\n    protected DiscoveryConfigRegisterDTO buildDiscoveryConfigRegisterDTO(final ShenyuDiscoveryConfig shenyuDiscoveryConfig, final String namespaceId) {\n        if (StringUtils.isEmpty(shenyuDiscoveryConfig.getServerList())) {\n            LOG.error(\"If using service discovery. The configuration shenyu.discovery.name in xml/yml cannot be null\");\n            throw new ShenyuException(\"The configuration shenyu.discovery.serverList in xml/yml cannot be null\");\n        }\n        if (StringUtils.isEmpty(shenyuDiscoveryConfig.getType())) {\n            LOG.error(\"If using service discovery. The configuration shenyu.discovery.name in xml/yml cannot be null\");\n            throw new ShenyuException(\"The configuration shenyu.discovery.type in xml/yml cannot be null\");\n        }\n        return DiscoveryConfigRegisterDTO.builder()\n                .name(discoveryName())\n                .selectorName(clientRegisterConfig.getContextPath())\n                .handler(\"{}\")\n                .listenerNode(shenyuDiscoveryConfig.getRegisterPath())\n                .serverList(shenyuDiscoveryConfig.getServerList())\n                .props(shenyuDiscoveryConfig.getProps())\n                .discoveryType(shenyuDiscoveryConfig.getType())\n                .pluginName(plugin.getName())\n                .namespaceId(namespaceId)\n                .build();\n    }\n\n    private String discoveryName() {\n        return \"default_\" + shenyuDiscoveryConfig.getType();\n    }\n","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/apache/shenyu/blob/567142e07261b3e615ae8850b30f4421f455cc5d/shenyu-client/shenyu-client-core/src/main/java/org/apache/shenyu/client/core/register/ClientDiscoveryConfigRefreshedEventListener.java#L70-L106","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Add the discovery type to your client config, e.g. `shenyu:\n  discovery:\n    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."],"exampleFix":"# before\nshenyu:\n  discovery:\n    serverList: localhost:2181\n# after\nshenyu:\n  discovery:\n    type: zookeeper\n    serverList: localhost:2181","handlingStrategy":"validation","validationCode":"// Spring boot startup check\n@PostConstruct\nvoid checkDiscoveryConfig() {\n    ShenyuClientConfig.DiscoveryConfig d = shenyuClientConfig.getDiscovery();\n    if (d == null || d.getType() == null || d.getType().isEmpty()) {\n        throw new IllegalStateException(\"shenyu.discovery.type must be set (e.g. zookeeper, nacos)\");\n    }\n    if (d.getServerList() == null || d.getServerList().isEmpty()) {\n        throw new IllegalStateException(\"shenyu.discovery.serverList must be set\");\n    }\n}","typeGuard":"boolean hasText(String s) { return s != null && !s.trim().isEmpty(); }","tryCatchPattern":null,"preventionTips":["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."],"tags":["config","discovery","client-registration"],"backgroundTag":"missing-required-config-field","analyzedSha":"567142e07261b3e615ae8850b30f4421f455cc5d","analyzedAt":"2026-09-12T10:08:21.293Z","contentChangedAt":"2026-09-12T10:08:21.293Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}