{"record":{"id":"763f448ab7dfd033","repo":"pinpoint-apm/pinpoint","slug":"webhook-url-scheme-is-required","errorCode":null,"errorMessage":"Webhook URL scheme is required","messagePattern":"Webhook URL scheme 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":109,"sourceCode":"\n        final URI uri;\n\n        try {\n            uri = new URI(url).normalize().parseServerAuthority();\n        } catch (URISyntaxException e) {\n            throw new IllegalArgumentException(\"Malformed webhook URL\", e);\n        }\n\n        validateScheme(uri);\n        validateAuthority(uri);\n\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        }","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/pinpoint-apm/pinpoint/blob/744c3d3075e595656abb1ae331ad2c0e4c9eb996/commons-server/src/main/java/com/navercorp/pinpoint/common/server/webhook/WebhookUrlValidator.java#L91-L127","documentation":"WebhookUrlValidator.validateScheme throws IllegalArgumentException when the parsed URI has no scheme component. The URL must declare http or https explicitly; a scheme-less URL cannot be dereferenced as an HTTP webhook target.","triggerScenarios":"Passing a URL like 'example.com/hook' or '//example.com/hook' (protocol-relative) to validateSyntax/uri — the URI parses but getScheme() returns null.","commonSituations":"Users entering host-only endpoints in webhook config assuming https is implied; protocol-relative URLs copied from browser-facing code; config values like 'localhost:8080/hook' where 'localhost' is parsed as the scheme.","solutions":["Prefix the URL with an explicit scheme: https://example.com/hook","Normalize user input: if the string lacks '://', prepend 'https://' before validating","Note that 'localhost:8080/hook' parses scheme='localhost' — use 'http://localhost:8080/hook'"],"exampleFix":"// before\nvalidator.validateSyntax(\"example.com/hook\");\n// after\nvalidator.validateSyntax(\"https://example.com/hook\");","handlingStrategy":"validation","validationCode":"if (!url.matches(\"^https?://.*\")) url = \"https://\" + url;","typeGuard":"boolean hasHttpScheme(java.net.URI uri) { String s = uri.getScheme(); return \"http\".equalsIgnoreCase(s) || \"https\".equalsIgnoreCase(s); }","tryCatchPattern":"try { WebhookUrlValidator.validateSyntax(url); } catch (IllegalArgumentException e) { if (e.getMessage().contains(\"scheme\")) { hint = \"add https:// prefix\"; } }","preventionTips":["Default missing schemes to https:// in input normalization","Warn users that 'host:port/path' strings parse 'host' as the scheme","Always use fully-qualified scheme://host URLs in configs"],"tags":["java","webhook","url","scheme"],"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"}