Description
onSelectorChanged does SelectorData selectorData = changed.stream().findFirst().orElseThrow(...); String configKeyPrefix = selectorData.getNamespaceId() + JOIN_POINT + changeData.getSelectorDataId() + JOIN_POINT; — using getNamespaceId() directly with no null-default. Every sibling handler (onAppAuthChanged:73-75, onPluginChanged:84-86, onMetaDataChanged:95-97, onRuleChanged:187-189, onProxySelectorChanged:276-278, onDiscoveryUpstreamChanged:287-289) wraps the value with StringUtils.defaultString(value.getNamespaceId(), SYS_DEFAULT_NAMESPACE_ID) before building the prefix. If a SelectorData arrives with null namespaceId, the prefix becomes the literal "null.selector." instead of "<default-namespace>.selector.". The gateway-side nacos/apollo reader builds keys with the configured namespace id, so it reads "<default>.selector." and never sees the entries written under "null.selector." — selectors silently invisible to the gateway.
Location
shenyu-admin-listener/shenyu-admin-listener-api/src/main/java/org/apache/shenyu/admin/listener/AbstractNodeDataChangedListener.java:176-177 (onSelectorChanged); compare siblings :73-75,:84-86,:95-97,:187-189,:276-278,:287-289
Impact
Latent: any selector with a null namespaceId (partial config, legacy data, or a future code path that forgets to set it) is published under a wrong config key on nacos/apollo/polaris and is invisible to gateways, causing those routes to vanish while admin shows them as registered. The sibling methods defend against exactly this; selector alone does not.
Suggested fix
Replace selectorData.getNamespaceId() at line 177 with StringUtils.defaultString(selectorData.getNamespaceId(), SYS_DEFAULT_NAMESPACE_ID) (and use the same streaming pattern as siblings to be consistent).
Related existing
None — distinct from CLI-2 (#6664, client-side new-registrar never propagates namespaceId) and CLI-3 (rpcExt case mismatch). This is admin-side config-key construction for selector publish on node-based backends.
Description
onSelectorChangeddoesSelectorData selectorData = changed.stream().findFirst().orElseThrow(...); String configKeyPrefix = selectorData.getNamespaceId() + JOIN_POINT + changeData.getSelectorDataId() + JOIN_POINT;— usinggetNamespaceId()directly with no null-default. Every sibling handler (onAppAuthChanged:73-75,onPluginChanged:84-86,onMetaDataChanged:95-97,onRuleChanged:187-189,onProxySelectorChanged:276-278,onDiscoveryUpstreamChanged:287-289) wraps the value withStringUtils.defaultString(value.getNamespaceId(), SYS_DEFAULT_NAMESPACE_ID)before building the prefix. If aSelectorDataarrives with nullnamespaceId, the prefix becomes the literal"null.selector."instead of"<default-namespace>.selector.". The gateway-side nacos/apollo reader builds keys with the configured namespace id, so it reads"<default>.selector."and never sees the entries written under"null.selector."— selectors silently invisible to the gateway.Location
shenyu-admin-listener/shenyu-admin-listener-api/src/main/java/org/apache/shenyu/admin/listener/AbstractNodeDataChangedListener.java:176-177(onSelectorChanged); compare siblings:73-75,:84-86,:95-97,:187-189,:276-278,:287-289Impact
Latent: any selector with a null
namespaceId(partial config, legacy data, or a future code path that forgets to set it) is published under a wrong config key on nacos/apollo/polaris and is invisible to gateways, causing those routes to vanish while admin shows them as registered. The sibling methods defend against exactly this; selector alone does not.Suggested fix
Replace
selectorData.getNamespaceId()at line 177 withStringUtils.defaultString(selectorData.getNamespaceId(), SYS_DEFAULT_NAMESPACE_ID)(and use the same streaming pattern as siblings to be consistent).Related existing
None — distinct from CLI-2 (#6664, client-side new-registrar never propagates namespaceId) and CLI-3 (rpcExt case mismatch). This is admin-side config-key construction for selector publish on node-based backends.