apache/pulsar · error · IllegalArgumentException

httpReverseProxy.%s.proxyTo must be specified exactly once

Error message

httpReverseProxy.%s.proxyTo must be specified exactly once

What it means

ProxyConfiguration.loadConfig validates that every httpReverseProxy.<name> block defines both a path and a proxyTo key exactly once. When a block omits httpReverseProxy.<name>.proxyTo (or path), the configuration cannot determine the upstream target the reverse proxy should forward to, so it refuses to start. This fail-fast validation prevents silently proxying to a null/undefined target.

Source

Thrown at pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/ProxyConfiguration.java:1120

    public void setProperties(Properties properties) {
        this.properties = properties;

        Map<String, Map<String, String>> redirects = new HashMap<>();
        Pattern redirectPattern = Pattern.compile("^httpReverseProxy\\.([^\\.]*)\\.(.+)$");
        Map<String, List<Matcher>> groups = properties.stringPropertyNames().stream()
            .map((s) -> redirectPattern.matcher(s))
            .filter(Matcher::matches)
            .collect(Collectors.groupingBy((m) -> m.group(1))); // group by name

        groups.entrySet().forEach((e) -> {
                Map<String, String> keyToFullKey = e.getValue().stream().collect(
                        Collectors.toMap(m -> m.group(2), m -> m.group(0)));
                if (!keyToFullKey.containsKey("path")) {
                    throw new IllegalArgumentException(
                            String.format("httpReverseProxy.%s.path must be specified exactly once", e.getKey()));
                }
                if (!keyToFullKey.containsKey("proxyTo")) {
                    throw new IllegalArgumentException(
                            String.format("httpReverseProxy.%s.proxyTo must be specified exactly once", e.getKey()));
                }
                httpReverseProxyConfigs.add(new HttpReverseProxyConfig(e.getKey(),
                                                    properties.getProperty(keyToFullKey.get("path")),
                                                    properties.getProperty(keyToFullKey.get("proxyTo"))));
            });
    }

    public static class HttpReverseProxyConfig {
        private final String name;
        private final String path;
        private final String proxyTo;

        HttpReverseProxyConfig(String name, String path, String proxyTo) {
            this.name = name;
            this.path = path;
            this.proxyTo = proxyTo;
        }

View on GitHub (pinned to 820761864e)

Solutions

  1. Add the missing key to the block, e.g. httpReverseProxy.<name>.proxyTo=http://localhost:8080
  2. Verify the key spelling is exactly 'proxyTo' (camelCase, no underscores) and both path and proxyTo exist for the same <name>
  3. Remove any orphaned/partial httpReverseProxy blocks for services no longer in use
  4. Validate config in CI by constructing ProxyConfiguration and calling loadConfig on the file before deploy

Example fix

// before
httpReverseProxy.functions.path=/admin/functions

// after
httpReverseProxy.functions.path=/admin/functions
httpReverseProxy.functions.proxyTo=http://localhost:6750
Defensive patterns

Strategy: validation

Validate before calling

Properties props = loadProperties();
Set<String> names = props.stringPropertyNames().stream()
    .filter(k -> k.startsWith("httpReverseProxy."))
    .map(k -> k.split("\\.")[1])
    .collect(Collectors.toSet());
for (String name : names) {
    if (props.getProperty("httpReverseProxy." + name + ".path") == null
            || props.getProperty("httpReverseProxy." + name + ".proxyTo") == null) {
        throw new IllegalArgumentException("httpReverseProxy." + name + " must define both path and proxyTo");
    }
}

Type guard

boolean hasCompleteReverseProxyBlock(Properties props, String name) {
    return props.getProperty("httpReverseProxy." + name + ".path") != null
        && props.getProperty("httpReverseProxy." + name + ".proxyTo") != null;
}

Try / catch

try {
    config.loadConfig(props);
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("httpReverseProxy")) {
        LOG.error("Invalid reverse proxy block, check path/proxyTo keys: {}", e.getMessage());
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling ProxyConfiguration.loadConfig with properties that contain an httpReverseProxy.<name> block where httpReverseProxy.<name>.path is set but httpReverseProxy.<name>.proxyTo is missing (or vice versa); also triggered when the regex key extraction yields a group whose key-to-fullKey map lacks the 'proxyTo' entry, e.g. duplicate/malformed key names like httpReverseProxy.<name>.proxyTo defined with a typo such as proxyto.

Common situations: Hand-editing proxy config files and typo-ing 'proxyTo' as 'proxyto' or 'proxy_to'; copy-pasting a reverse-proxy block from docs and deleting the proxyTo line; leaving a stale block behind after removing an upstream service; migration from older configs that only had path.

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/f991fd94e9385a20. Report an issue: GitHub.