apache/shenyu · error · ShenyuException

sync.consul.url formatter is not incorrect.

Error message

sync.consul.url formatter is not incorrect.

What it means

This error is thrown when ShenYu initializes the Consul config-sync client at startup and the configured `shenyu.sync.consul.url` property cannot be parsed by `java.net.URL` as a valid absolute URL. The starter wraps the resulting `MalformedURLException` in a `ShenyuException`, which fails the Spring bean creation of `ConsulClient` and therefore aborts gateway bootstrapping. The message wording is awkward (it means the URL format is incorrect, not a formatter issue), but the cause is always a malformed `sync.consul.url` value.

Solutions

  1. Add a valid scheme to `shenyu.sync.consul.url`, e.g. `http://localhost:8500` instead of `localhost:8500`
  2. Verify the property value has no stray spaces, quotes, or invisible characters (check the exact value in your application.yml/properties or environment variable)
  3. Ensure the port is numeric and in range (1-65535); remove placeholders like `${CONSUL_URL}` left unresolved
  4. Cross-check against the ShenYu docs example config for the consul sync starter and restart after fixing

Example fix

# before (application.yml) — missing scheme, not a parseable URL
shenyu:
  sync:
    consul:
      url: localhost:8500
# after
shenyu:
  sync:
    consul:
      url: http://localhost:8500
Defensive patterns

Strategy: validation

Validate before calling

public static void validateConsulUrl(String url) {
    if (url == null || url.isBlank()) {
        throw new IllegalArgumentException("shenyu.sync.consul.url is required");
    }
    try {
        java.net.URL u = new java.net.URI(url).toURL();
        if (u.getHost() == null) {
            throw new IllegalArgumentException("shenyu.sync.consul.url must include a host, e.g. http://localhost:8500");
        }
    } catch (Exception e) {
        throw new IllegalArgumentException("shenyu.sync.consul.url is not a valid URL: " + url, e);
    }
}

Type guard

public static boolean isValidUrl(String url) {
    if (url == null || url.isBlank()) {
        return false;
    }
    try {
        return new java.net.URI(url).toURL().getHost() != null;
    } catch (Exception e) {
        return false;
    }
}

Try / catch

try {
    ConsulClient client = buildConsulClient(config.getUrl());
} catch (ShenyuException e) {
    if (e.getMessage().contains("sync.consul.url formatter")) {
        log.error("Invalid shenyu.sync.consul.url '{}': must be an absolute URL like http://host:8500", config.getUrl(), e);
    }
    throw e; // fail fast: the gateway cannot sync config without Consul
}

Prevention

When it happens

Trigger: Spring bean `consulClient` in ConsulSyncDataConfiguration calls `new URL(url)` where `url` comes from `shenyu.sync.consul.url` in application.yml/properties; if the value is not a parseable absolute URL (e.g. missing scheme like `localhost:8500`, illegal characters, spaces, or a bad port like `http://consul:port`), `MalformedURLException` is thrown and rethrown as this ShenyuException.

Common situations: Developers set `shenyu.sync.consul.url: localhost:8500` forgetting the `http://` scheme (the most common case, since a plain host:port is not a valid URL), paste URLs with trailing spaces or quotes, use an invalid port number, or point at a scheme like `https` with typo characters. It typically surfaces immediately on gateway startup with a bean-creation stack trace.

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


AI-assisted analysis of apache/shenyu@567142e072 (2026-09-12). Data as JSON: /api/errors/9b5fed4f8659bf48. Report an issue: GitHub.

Appendix: source

Thrown at shenyu-spring-boot-starter/shenyu-spring-boot-starter-sync-data-center/shenyu-spring-boot-starter-sync-data-consul/src/main/java/org/apache/shenyu/springboot/sync/data/consul/ConsulSyncDataConfiguration.java:111

    }


    /**
     * init Consul client.
     * @param consulConfig the consul config
     * @return Consul client
     */
    @Bean
    public ConsulClient consulClient(final ConsulConfig consulConfig) {
        String url = consulConfig.getUrl();
        if (StringUtils.isBlank(url)) {
            throw new ShenyuException("sync.consul.url can not be null.");
        }
        try {
            URL consulUrl = new URL(url);
            return consulUrl.getPort() < 0 ? new ConsulClient(consulUrl.getHost()) : new ConsulClient(consulUrl.getHost(), consulUrl.getPort());
        } catch (MalformedURLException e) {
            throw new ShenyuException("sync.consul.url formatter is not incorrect.");
        }
    }
}

View on GitHub (pinned to 567142e072)