Sentry provider crash-loops the backend at startup when Sentry returns an error with an empty body
Summary
Provisioning a sentry provider via KEEP_PROVIDERS against a current Sentry SaaS org crash-loops keep-backend, taking the whole deployment down rather than reporting a failed scope.
Root cause
SentryProvider.validate_scopes() assumes every non-ok response carries a JSON body and calls response.json() on five error paths. Sentry does not guarantee that — a 404 from an endpoint that no longer exists returns an empty body — so response.json() raises:
JSONDecodeError: Expecting value: line 1 column 1 (char 0)ProvidersService.provision_providers() calls validate_scopes() at application startup and does not catch the exception, so this is fatal rather than contained.
Why it triggers on a normal setup
The project:write check POSTs to the legacy per-project endpoint:
POST /projects/{org}/{project}/plugins/webhooks/That endpoint is gone from modern Sentry SaaS, which answers 404 with an empty body — hitting the unguarded .json() directly.
Reproduce
- Create a Sentry org-level internal integration token.
- Provision a sentry provider through
KEEP_PROVIDERS, e.g.{"my-sentry":{"type":"sentry","authentication":{"api_key":"…","organization_slug":"…"}}} - Start the backend.
keep-backend crash-loops on the trace above.
Ruled out by experiment
| Attempt | Result |
|---|---|
"install_webhook": false |
no effect — validate_scopes runs during install regardless |
Removing project:write from the token |
no effect — the POST still 404s with an empty body |
| Upgrading | no effect — the same POST is on main today |
Notable asymmetry
Installing the same provider via POST /providers/install returns a clean HTTP 412 and the backend survives. Only the startup provisioning path is fatal, which is what made this surprising to hit.
Versions
Observed on 0.54.2; the same code is on main.
Fix
PR #6807 makes the error-detail extraction tolerant of a missing/non-dict/unparseable body across all five paths, so a failed scope is reported rather than raised.
Note project:write is mandatory=False (mandatory_for_webhook=True), so with the crash fixed, install succeeds and only webhook installation is affected. Whether project:write should still probe the removed plugins/webhooks endpoint is a separate question — happy to address it if you'd like it in the same PR.
Source: keephq/keep