apache/shenyu · error · IllegalArgumentException
Invalid upstream URL, expected 'host:port' format but was:
Error message
Invalid upstream URL, expected 'host:port' format but was:
What it means
DiscoveryTransfer.mapToDiscoveryUpstreamData converts a CommonUpstream into DiscoveryUpstreamData and requires upstreamUrl in 'host:port' form. Splitting on ':' must yield at least 2 parts; if it doesn't (no colon or null already handled earlier), IllegalArgumentException is thrown.
Solutions
- Register the upstream with an explicit 'host:port' URL, e.g. '192.168.1.10:8080'
- Fix the source discovery data (nacos/zk/etcd instance metadata) to include the port
- If using IPv6, wrap the address in brackets with the port: '[::1]:8080' or pre-normalize before transfer
- Inspect CommonUpstream producers to ensure they always populate a port-bearing upstreamUrl
Example fix
// before
commonUpstream.setUpstreamUrl("my-service");
// after
commonUpstream.setUpstreamUrl("my-service:8080"); Defensive patterns
Strategy: validation
Validate before calling
boolean validUpstream = url != null && url.matches("[^:]+:\\d{1,5}"); Type guard
boolean isHostPort(String url) { int i = url.indexOf(':'); return i > 0 && i < url.length() - 1 && url.substring(i + 1).chars().allMatch(Character::isDigit); } Try / catch
try { transfer.mapToDiscoveryUpstreamData(upstream); } catch (IllegalArgumentException e) { log.error("bad upstream {}", upstream.getUpstreamUrl(), e); skipEntry(); } Prevention
- Always register upstreams with explicit numeric ports
- Validate the host:port form in dashboard forms and registration APIs
- Normalize full URLs (strip scheme/path) before storing upstreamUrl
- Bracket IPv6 hosts: '[::1]:8080'
When it happens
Trigger: A discovery upstream URL registered without a port — e.g. 'myhost' or 'http://myhost' style URLs where the split on ':' (limit 2) produces fewer than 2 parts — reaches mapToDiscoveryUpstreamData during discovery config sync/transfer.
Common situations: Registering backend instances without explicit ports in the dashboard or via client auto-registration; zookeeper/nacos/etcd discovery nodes storing bare hostnames; IPv6 addresses (multiple colons) breaking the naive split; upstream entries created before a format change in a newer ShenYu version.
Understand the failure class
Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.
Related errors
- Invalid port in upstream URL:
- before start ProxySelector you need init DiscoveryId=
- before start ProxySelector you need init DiscoveryId=
- shenyu discovery start watcher need you has this key
- shenyu discovery mode current didn't support
AI-assisted analysis of apache/shenyu@567142e072 (2026-09-12).
Data as JSON: /api/errors/52f1b546249f14b6.
Report an issue: GitHub.
Appendix: source
Thrown at shenyu-admin/src/main/java/org/apache/shenyu/admin/transfer/DiscoveryTransfer.java:356
discoveryUpstreamDTO.setDateCreated(data.getDateCreated());
discoveryUpstreamDTO.setDateUpdated(data.getDateUpdated());
return discoveryUpstreamDTO;
}).orElse(null);
}
/**
* mapToDiscoveryUpstreamData.
*
* @param commonUpstream commonUpstream
* @return DiscoveryUpstreamData
*/
public DiscoveryUpstreamData mapToDiscoveryUpstreamData(CommonUpstream commonUpstream) {
String upstreamUrl = commonUpstream.getUpstreamUrl();
String[] parts = Optional.ofNullable(upstreamUrl)
.map(url -> url.split(":", 2))
.orElseThrow(() -> new IllegalArgumentException("Upstream URL must not be null"));
if (parts.length < 2) {
throw new IllegalArgumentException("Invalid upstream URL, expected 'host:port' format but was: " + upstreamUrl);
}
String host = parts[0];
int port;
try {
port = Integer.parseInt(parts[1]);
} catch (NumberFormatException ex) {
throw new IllegalArgumentException("Invalid port in upstream URL: " + upstreamUrl, ex);
}
DiscoveryUpstreamDTO discoveryUpstreamDTO = CommonUpstreamUtils.buildDefaultDiscoveryUpstreamDTO(
host,
port,
commonUpstream.getProtocol(),
commonUpstream.getNamespaceId());
Properties properties = Optional.ofNullable(discoveryUpstreamDTO.getProps())
.map(props -> GsonUtils.getInstance().fromJson(props, Properties.class))
.orElse(new Properties());
properties.setProperty("healthCheckEnabled", String.valueOf(commonUpstream.isHealthCheckEnabled()));
discoveryUpstreamDTO.setProps(GsonUtils.getInstance().toJson(properties));View on GitHub (pinned to 567142e072)