{"record":{"id":"1708642ec0aea260","repo":"pinpoint-apm/pinpoint","slug":"webhook-url-host-is-required","errorCode":null,"errorMessage":"Webhook URL host is required","messagePattern":"Webhook URL host is required","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"commons-server/src/main/java/com/navercorp/pinpoint/common/server/webhook/WebhookUrlValidator.java","lineNumber":120,"sourceCode":"\n        return uri;\n    }\n\n    private static void validateScheme(URI uri) {\n        String scheme = uri.getScheme();\n        if (scheme == null) {\n            throw new IllegalArgumentException(\"Webhook URL scheme is required\");\n        }\n\n        String normalizedScheme = scheme.toLowerCase(Locale.ROOT);\n        if (!\"http\".equals(normalizedScheme) && !\"https\".equals(normalizedScheme)) {\n            throw new IllegalArgumentException(\"Webhook URL scheme must be http or https\");\n        }\n    }\n\n    private static void validateAuthority(URI uri) {\n        if (uri.getHost() == null || uri.getHost().isBlank()) {\n            throw new IllegalArgumentException(\"Webhook URL host is required\");\n        }\n        if (isBlockedHostLiteral(uri.getHost())) {\n            throw new IllegalArgumentException(\"Webhook URL host is not allowed\");\n        }\n        if (uri.getRawUserInfo() != null) {\n            throw new IllegalArgumentException(\"Webhook URL user info is not allowed\");\n        }\n        if (uri.getRawFragment() != null) {\n            throw new IllegalArgumentException(\"Webhook URL fragment is not allowed\");\n        }\n        int port = uri.getPort();\n        if (port == -1 && hasExplicitPort(uri)) {\n            throw new IllegalArgumentException(\"Webhook URL port is not valid\");\n        }\n        if (port == 0 || port > MAX_PORT) {\n            throw new IllegalArgumentException(\"Webhook URL port is not allowed\");\n        }\n    }","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/pinpoint-apm/pinpoint/blob/744c3d3075e595656abb1ae331ad2c0e4c9eb996/commons-server/src/main/java/com/navercorp/pinpoint/common/server/webhook/WebhookUrlValidator.java#L102-L138","documentation":"WebhookUrlValidator.validateAuthority throws IllegalArgumentException when the parsed URI has no host component (getHost() null or blank). Even with a valid scheme, an HTTP webhook needs a resolvable host.","triggerScenarios":"URLs like 'http://' or 'https:///path' where the authority part is empty; a URL whose authority failed to parse so getHost() returns null.","commonSituations":"Truncated URL in config after the host was accidentally deleted; 'http://%20' style garbage input; form submitted with only scheme typed.","solutions":["Include a host in the URL: https://example.com/hook","Validate that the configured endpoint host resolves (DNS) before saving the webhook","Check for copy/paste truncation of the URL in the config source"],"exampleFix":"// before\nvalidator.validateSyntax(\"https:///webhook\");\n// after\nvalidator.validateSyntax(\"https://example.com/webhook\");","handlingStrategy":"validation","validationCode":"if (!url.matches(\"^https?://[^/]+.*\")) reject(url);","typeGuard":"boolean hasHost(java.net.URI uri) { return uri.getHost() != null && !uri.getHost().isBlank(); }","tryCatchPattern":"try { WebhookUrlValidator.validateSyntax(url); } catch (IllegalArgumentException e) { if (e.getMessage().contains(\"host is required\")) { form.reject(\"url\", \"host is missing\"); } }","preventionTips":["Avoid copy/paste truncation — preview the full URL before saving","Resolve the host with DNS lookup before accepting the webhook config","Require full scheme://host[:port]/path form"],"tags":["java","webhook","url","host"],"backgroundTag":"invalid-url-format","analyzedSha":"744c3d3075e595656abb1ae331ad2c0e4c9eb996","analyzedAt":"2026-09-07T18:48:45.289Z","contentChangedAt":"2026-09-07T18:48:45.289Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}