apache/skywalking · error · IllegalArgumentException

PagerDuty hook: [{hookName}] events-api-url must be an absol

Error message

PagerDuty hook: [{hookName}] events-api-url must be an absolute http(s) URL, but was: [{url}].

What it means

IllegalArgumentException thrown by RulesReader.validateEventsApiUrl when the events-api-url parses as a URI but is not an absolute http(s) URL — either uri.getHost() is null (relative/authority-less URI) or the scheme is not http/https (e.g. ftp, mailto). PagerDuty notifications are sent as HTTP POSTs, so the client needs an absolute URL with a host.

Source

Thrown at oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/RulesReader.java:407

     * Rejects a malformed `events-api-url` while the config is being read, so a typo fails startup (or the dynamic
     * config update) instead of surfacing later as a per-alarm {@link URI#create} failure inside the hook callback,
     * where every alarm would be dropped with only an error log.
     *
     * @param url      the configured endpoint
     * @param hookName the hook the endpoint belongs to, for the error message
     */
    private void validateEventsApiUrl(String url, String hookName) {
        final URI uri;
        try {
            uri = new URI(url);
        } catch (URISyntaxException e) {
            throw new IllegalArgumentException(
                    "PagerDuty hook: [" + hookName + "] events-api-url is malformed: [" + url + "].", e);
        }
        final String scheme = uri.getScheme();
        if (uri.getHost() == null
                || !("https".equalsIgnoreCase(scheme) || "http".equalsIgnoreCase(scheme))) {
            throw new IllegalArgumentException(
                    "PagerDuty hook: [" + hookName + "] events-api-url must be an absolute http(s) URL, but was: ["
                            + url + "].");
        }
        // The integration key travels in the request body, so a non-TLS endpoint puts a credential on the wire.
        if (!"https".equalsIgnoreCase(scheme)) {
            log.warn(
                    "PagerDuty hook [{}] is configured with a non-https events-api-url [{}]. "
                            + "The integration key is sent in the request body and will not be encrypted.",
                    hookName, url
            );
        }
    }

    /**
     * Read PagerDuty hook config into {@link PagerDutySettings}
     */
    @SuppressWarnings("unchecked")
    private void readPagerDutyConfig(Map hooks, Rules rules) {

View on GitHub (pinned to 102af09b4a)

Solutions

  1. Prefix the URL with the scheme: `https://events.pagerduty.com/v2/enqueue`.
  2. Note the follow-up warn: an http:// URL is accepted but the integration key travels unencrypted in the request body — prefer https, or use an http URL only against a TLS-terminating internal proxy.
  3. If using templating, ensure the template renders scheme+host+path together, not just the host.
  4. Restart OAP / re-push the config after fixing; validation is fail-fast at config read.

Example fix

# before
hooks:
  pagerduty:
    pagerduty-hook:
      events-api-url: events.pagerduty.com/v2/enqueue  # no scheme, host==null
# after
hooks:
  pagerduty:
    pagerduty-hook:
      events-api-url: https://events.pagerduty.com/v2/enqueue
Defensive patterns

Strategy: validation

Validate before calling

// Accept only absolute http(s) with host, mirroring RulesReader:
URI u = URI.create(url);
boolean ok = u.getHost() != null
    && ("https".equalsIgnoreCase(u.getScheme()) || "http".equalsIgnoreCase(u.getScheme()));

Prevention

When it happens

Trigger: A PagerDuty hook URL like `events.pagerduty.com/v2/enqueue` (no scheme, so URI treats the whole thing as a path and host is null), `localhost:8080/x` without `http://` (parsed as scheme `localhost`), or a non-http scheme such as `ftp://...`. Only `http` and `https` (case-insensitive) with a non-null host pass.

Common situations: Omitting the scheme when editing config by hand; an env-var template that injects only the host part; using a service-short-name URL in Kubernetes (`http://pagerduty-proxy.svc` is fine but `pagerduty-proxy.svc` alone fails); switching from a fully-qualified URL to an internal short name and dropping `http://`.

Related errors


AI-assisted analysis of apache/skywalking@102af09b4a (2026-08-14). Data as JSON: /api/errors/542fd85884ccaa62. Report an issue: GitHub.