{"record":{"id":"eacb3322c30ded44","repo":"pinpoint-apm/pinpoint","slug":"missing-argument-webhook-id","errorCode":null,"errorMessage":"Missing argument: webhook.id","messagePattern":"Missing argument: webhook\\.id","errorType":"validation","errorClass":"ResponseStatusException","httpStatus":400,"severity":"warning","filePath":"webhook/src/main/java/com/navercorp/pinpoint/web/webhook/controller/WebhookController.java","lineNumber":68,"sourceCode":"        }\n\n        try {\n            validateURL(webhook);\n        } catch (IllegalArgumentException e) {\n            logger.info(\"Invalid argument: webhook.url\");\n            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, \"Invalid argument: webhook.url\");\n        }\n\n        String webhookId = webhookService.insertWebhook(webhook);\n        return new WebhookResponse(Result.SUCCESS, webhookId);\n    }\n\n    @DeleteMapping()\n    public Response deleteWebhook(@RequestBody Webhook webhook) {\n\n        if (!StringUtils.hasText(webhook.getWebhookId())) {\n            logger.info(\"Missing argument: webhookId\");\n            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, \"Missing argument: webhook.id\");\n        }\n        webhookService.deleteWebhook(webhook);\n        return SimpleResponse.ok();\n    }\n\n    @GetMapping()\n    public List<Webhook> getWebhook(@RequestParam(value=APPLICATION_ID, required=false) String applicationName,\n                                    @RequestParam(value=SERVICE_NAME, required=false) String serviceName,\n                                    @RequestParam(value=ALARM_RULE_ID, required=false) String ruleId) {\n\n        if (!StringUtils.hasText(applicationName) && !StringUtils.hasText(serviceName) && !StringUtils.hasText(ruleId)) {\n            logger.info(\"Missing argument: applicationId/serviceName/ruleId\");\n            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, \"Missing argument: applicationId / serviceName / ruleId\");\n        }\n\n        if (StringUtils.hasText(ruleId)) {\n            return webhookService.selectWebhookByRuleId(ruleId);\n        }","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/pinpoint-apm/pinpoint/blob/744c3d3075e595656abb1ae331ad2c0e4c9eb996/webhook/src/main/java/com/navercorp/pinpoint/web/webhook/controller/WebhookController.java#L50-L86","documentation":"Pinpoint Web's WebhookController.deleteWebhook requires the request body JSON to carry a non-empty webhookId. Because @RequestBody deserializes into a Webhook POJO, a missing or empty 'webhookId' field passes controller binding and is only caught by this explicit StringUtils.hasText check, which then throws a Spring ResponseStatusException mapped to HTTP 400.","triggerScenarios":"Calling DELETE /webhook with a JSON body like {} or {\"webhookId\":\"\"} or a body omitting the webhookId field entirely; also happens when the client sends a differently-cased key (e.g. webhook_id) that Jackson leaves null on the Webhook object.","commonSituations":"Scripts deleting webhooks from a saved export that lacks the id field; clients built against an older API where the id was passed as a query parameter; automation sending null ids after a failed lookup of the webhook to delete.","solutions":["Include a non-empty webhookId string field in the DELETE request body, e.g. {\"webhookId\":\"<existing-id>\"}","Verify the field name and casing exactly matches webhookId as defined in the Webhook DTO","Fetch the webhook id first via GET /webhook?applicationId=... or ?ruleId=... if unknown","Ensure the HTTP client actually serializes the body (Content-Type: application/json, non-empty payload)"],"exampleFix":"// before\ncurl -X DELETE http://pinpoint/webhook -H 'Content-Type: application/json' -d '{}'\n// after\ncurl -X DELETE http://pinpoint/webhook -H 'Content-Type: application/json' -d '{\"webhookId\":\"e2f1a3b4c5d6\"}'","handlingStrategy":"validation","validationCode":"if (webhook == null || webhook.getWebhookId() == null || webhook.getWebhookId().isBlank()) { throw new IllegalArgumentException(\"webhookId is required to delete a webhook\"); }","typeGuard":"boolean isDeletable(Webhook w) { return w != null && w.getWebhookId() != null && !w.getWebhookId().isBlank(); }","tryCatchPattern":"try { webhookService.deleteWebhook(webhook); } catch (HttpStatusCodeException e) { if (e.getStatusCode() == HttpStatus.BAD_REQUEST) { /* inspect webhookId field */ } throw e; }","preventionTips":["Always source webhookId from a prior GET /webhook lookup, never hardcode","Log the exact request body before sending so missing fields are visible","Use a typed client/DTO mirroring the Webhook fields instead of hand-built JSON","Add a client-side hasText check on webhookId before any webhook write/delete call"],"tags":["http-400","rest-api","validation","webhook"],"backgroundTag":"missing-required-argument","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"}