{"record":{"id":"31d0d791aee5ae2d","repo":"SonarSource/sonarqube","slug":"maximum-number-of-global-webhooks-reached","errorCode":null,"errorMessage":"Maximum number of global webhooks reached","messagePattern":"Maximum number of global webhooks reached","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":400,"severity":"error","filePath":"server/sonar-webserver-webapi/src/main/java/org/sonar/server/webhook/ws/CreateAction.java","lineNumber":180,"sourceCode":"      .setUrl(dto.getUrl())\n      .setHasSecret(dto.getSecret() != null);\n    writeProtobuf(newBuilder().setWebhook(webhookBuilder).build(), request, response);\n  }\n\n  private static void checkNumberOfWebhook(int nbOfWebhooks, String projectKey) {\n    if (nbOfWebhooks >= MAX_NUMBER_OF_WEBHOOKS) {\n      throw new IllegalArgumentException(format(\"Maximum number of webhook reached for project '%s'\", projectKey));\n    }\n  }\n\n  private int numberOfWebhookOf(DbSession dbSession, ProjectDto projectDto) {\n    return dbClient.webhookDao().selectByProject(dbSession, projectDto).size();\n  }\n\n  private void checkNumberOfGlobalWebhooks(DbSession dbSession) {\n    int globalWebhooksCount = dbClient.webhookDao().selectGlobalWebhooks(dbSession).size();\n    if (globalWebhooksCount >= MAX_NUMBER_OF_WEBHOOKS) {\n      throw new IllegalArgumentException(\"Maximum number of global webhooks reached\");\n    }\n  }\n}\n","sourceCodeStart":162,"sourceCodeEnd":184,"githubUrl":"https://github.com/SonarSource/sonarqube/blob/184c821202192afc1c599fc912d0889b69fffa53/server/sonar-webserver-webapi/src/main/java/org/sonar/server/webhook/ws/CreateAction.java#L162-L184","documentation":"Thrown by CreateAction.checkNumberOfGlobalWebhooks when creating a global (project-less) webhook and the count of existing global webhooks already equals MAX_NUMBER_OF_WEBHOOKS. The api/webhooks/create endpoint returns a 400 IllegalArgumentException when the cap is hit.","triggerScenarios":"POST api/webhooks/create without a 'project' parameter while the instance already has the maximum number of global webhooks.","commonSituations":"Automated setup scripts that add a global webhook on every environment bootstrap; org-wide integrations accumulating after instance consolidation; repeated non-idempotent provisioning runs.","solutions":["List global webhooks with GET api/webhooks/list and delete stale ones via api/webhooks/delete.","Update an existing global webhook (api/webhooks/update) rather than adding another.","Move integration to project-level webhooks where per-project limits are separate."],"exampleFix":"// before\ncurl -u $ADMIN_TOKEN -X POST \"$SONAR/api/webhooks/create?name=org-hook&url=$URL\" // fails at cap\n// after\nCOUNT=$(curl -su $ADMIN_TOKEN \"$SONAR/api/webhooks/list\" | jq '.webhooks | length')\nif [ \"$COUNT\" -lt 10 ]; then curl -u $ADMIN_TOKEN -X POST \"$SONAR/api/webhooks/create?name=org-hook&url=$URL\"; fi","handlingStrategy":"validation","validationCode":"COUNT=$(curl -su \"$ADMIN_TOKEN\" \"$SONAR/api/webhooks/list\" | jq '.webhooks | length')\n[ \"$COUNT\" -lt 10 ] || echo \"global webhook cap reached\"","typeGuard":null,"tryCatchPattern":"try {\n  createGlobalWebhook(...);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().contains(\"Maximum number of global webhooks reached\")) {\n    updateExistingGlobalWebhookInstead();\n  }\n}","preventionTips":["Check-then-create (or update-in-place) in bootstrap scripts.","Consolidate global webhooks into one relay endpoint rather than many.","Audit global webhooks periodically with api/webhooks/list."],"tags":["webhook","limit-exceeded","web-api","global"],"backgroundTag":"rate-limit-exceeded","analyzedSha":"184c821202192afc1c599fc912d0889b69fffa53","analyzedAt":"2026-09-09T12:23:51.573Z","contentChangedAt":"2026-09-09T12:23:51.573Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}