Skip to content

Commit aa19aeb

Browse files
julianknutsenclaude
andcommitted
fix: suppress Sentry noise for DoltHub token permission errors
The DOLTHUB_TOKEN lacks SQL permissions on hop/wl-commons, causing handleBrowse and handleDashboard to capture the same config error to Sentry on every request (93+ events). Adds isTokenPermissionError classifier to suppress captures and return a specific error message. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 919d19f commit aa19aeb

1 file changed

Lines changed: 21 additions & 5 deletions

File tree

internal/api/handlers.go

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,11 @@ func (s *Server) handleBrowse(w http.ResponseWriter, r *http.Request) {
7777
}
7878
// No stale data — return a 503 with a clear outage message.
7979
msg := "Upstream database is temporarily unavailable — please try again in a moment."
80+
if isTokenPermissionError(err) {
81+
msg = "DoltHub API token lacks SQL permissions — check token configuration."
82+
}
8083
slog.Error("browse failed with no stale data", "error", err)
81-
if !isTransientUpstreamError(err) {
84+
if !isTransientUpstreamError(err) && !isTokenPermissionError(err) {
8285
sentry.CaptureException(err)
8386
}
8487
writeJSON(w, http.StatusServiceUnavailable, ErrorResponse{Error: msg})
@@ -126,8 +129,11 @@ func (s *Server) handleDetail(w http.ResponseWriter, r *http.Request) {
126129
return
127130
}
128131
msg := "Upstream database is temporarily unavailable — please try again in a moment."
132+
if isTokenPermissionError(err) {
133+
msg = "DoltHub API token lacks SQL permissions — check token configuration."
134+
}
129135
slog.Error("detail failed with no stale data", "error", err)
130-
if !isTransientUpstreamError(err) {
136+
if !isTransientUpstreamError(err) && !isTokenPermissionError(err) {
131137
sentry.CaptureException(err)
132138
}
133139
writeJSON(w, http.StatusServiceUnavailable, ErrorResponse{Error: msg})
@@ -254,6 +260,13 @@ func isTransientUpstreamError(err error) bool {
254260
return strings.Contains(err.Error(), "no such repository")
255261
}
256262

263+
// isTokenPermissionError returns true if the error indicates the DoltHub API
264+
// token lacks the required permissions (e.g. SQL access). This is a persistent
265+
// configuration issue that won't self-resolve, so it should not flood Sentry.
266+
func isTokenPermissionError(err error) bool {
267+
return strings.Contains(err.Error(), "API token is not allowed to operate on this resource")
268+
}
269+
257270
// writeUpstreamError classifies DoltHub errors and writes an appropriate response:
258271
// - "invalid authorization" → 401 (triggers frontend re-auth)
259272
// - other upstream errors → 503 with sanitized message + Sentry capture
@@ -263,11 +276,14 @@ func writeUpstreamError(w http.ResponseWriter, err error, label string) {
263276
return
264277
}
265278
slog.Error(label+" failed", "error", err)
266-
if !isTransientUpstreamError(err) {
279+
if !isTransientUpstreamError(err) && !isTokenPermissionError(err) {
267280
sentry.CaptureException(err)
268281
}
269-
writeError(w, http.StatusServiceUnavailable,
270-
"Upstream database is temporarily unavailable — please try again in a moment.")
282+
msg := "Upstream database is temporarily unavailable — please try again in a moment."
283+
if isTokenPermissionError(err) {
284+
msg = "DoltHub API token lacks SQL permissions — check token configuration."
285+
}
286+
writeError(w, http.StatusServiceUnavailable, msg)
271287
}
272288

273289
// writeMutationError writes a 409 for ConflictError, 400 for everything else.

0 commit comments

Comments
 (0)