Skip to content

Commit bb1a2ef

Browse files
author
Julia Hoge
authored
fix(discord): Add more unactionable status codes to ignore from slo (#66903)
After an alert rule is created, the user can perform actions that can break the alert and produce error Discord API responses. For our SLO that monitors Discord response status codes, we _do_ want to keep track of responses that indicate a problem from our end i.e. 50109 (the request body contains invalid JSON.). We _don't_ want to keep track of responses that are failing because of a user config change. In order to make the SLO more relevant, we want to ignore specific discord provided codes that can be returned when a user changes a configuration and breaks the alert. Complete list of codes: https://discord.com/developers/docs/topics/opcodes-and-status-codes#http See `DISCORD_USER_ERRORS` for what is being ignored and why.
1 parent b558535 commit bb1a2ef

File tree

3 files changed

+264
-7
lines changed

3 files changed

+264
-7
lines changed

src/sentry/integrations/discord/client.py

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from __future__ import annotations
22

3-
# to avoid a circular import
43
import logging
54
from collections.abc import Mapping
65
from urllib.parse import urlencode
@@ -11,7 +10,10 @@
1110
from sentry import options
1211
from sentry.integrations.client import ApiClient
1312
from sentry.integrations.discord.message_builder.base.base import DiscordMessageBuilder
14-
from sentry.utils import metrics
13+
from sentry.integrations.discord.utils.consts import DISCORD_ERROR_CODES, DISCORD_USER_ERRORS
14+
15+
# to avoid a circular import
16+
from sentry.utils import json, metrics
1517

1618
logger = logging.getLogger("sentry.integrations.discord")
1719

@@ -115,17 +117,27 @@ def track_response_data(
115117
resp: Response | None = None,
116118
extra: Mapping[str, str] | None = None,
117119
) -> None:
120+
discord_code = ""
121+
code_message = ""
122+
123+
try:
124+
discord_response = json.loads(resp.content.decode("utf-8")) if resp else {}
125+
discord_code = discord_response.get("code")
126+
if discord_code in DISCORD_ERROR_CODES:
127+
code_message = DISCORD_ERROR_CODES[discord_code]
128+
129+
except Exception:
130+
pass
131+
118132
is_ok = code in {
119133
status.HTTP_200_OK,
120134
status.HTTP_201_CREATED,
121135
status.HTTP_202_ACCEPTED,
122136
status.HTTP_204_NO_CONTENT,
123137
}
124-
include_in_slo = code not in {
125-
status.HTTP_429_TOO_MANY_REQUESTS,
126-
status.HTTP_403_FORBIDDEN, # Is user error
127-
}
128138

139+
# These are excluded since they are not actionable from our side
140+
include_in_slo = discord_code not in DISCORD_USER_ERRORS
129141
metrics.incr(
130142
f"{self.metrics_prefix}.http_response",
131143
sample_rate=1.0,
@@ -134,14 +146,18 @@ def track_response_data(
134146
"status": code,
135147
"is_ok": is_ok,
136148
"include_in_slo": include_in_slo,
149+
"discord_code": discord_code,
137150
},
138151
)
139152

140153
log_params = {
141154
**(extra or {}),
142155
"status_string": str(code),
143156
"error": str(error)[:256] if error else None,
157+
"discord_code": discord_code,
158+
"code_message": code_message,
144159
}
160+
145161
if self.integration_type:
146162
log_params[self.integration_type] = self.name
147163

Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
# Complete list of discord error codes:
2+
# https://discord.com/developers/docs/topics/opcodes-and-status-codes#http
3+
4+
DISCORD_ERROR_CODES = {
5+
"0": "General error (such as a malformed request body, amongst other things)",
6+
"10001": "Unknown account",
7+
"10002": "Unknown application",
8+
"10003": "Unknown channel",
9+
"10004": "Unknown guild",
10+
"10005": "Unknown integration",
11+
"10006": "Unknown invite",
12+
"10007": "Unknown member",
13+
"10008": "Unknown message",
14+
"10009": "Unknown permission overwrite",
15+
"10010": "Unknown provider",
16+
"10011": "Unknown role",
17+
"10012": "Unknown token",
18+
"10013": "Unknown user",
19+
"10014": "Unknown emoji",
20+
"10015": "Unknown webhook",
21+
"10016": "Unknown webhook service",
22+
"10020": "Unknown session",
23+
"10026": "Unknown ban",
24+
"10027": "Unknown SKU",
25+
"10028": "Unknown Store Listing",
26+
"10029": "Unknown entitlement",
27+
"10030": "Unknown build",
28+
"10031": "Unknown lobby",
29+
"10032": "Unknown branch",
30+
"10033": "Unknown store directory layout",
31+
"10036": "Unknown redistributable",
32+
"10038": "Unknown gift code",
33+
"10049": "Unknown stream",
34+
"10050": "Unknown premium server subscribe cooldown",
35+
"10057": "Unknown guild template",
36+
"10059": "Unknown discoverable server category",
37+
"10060": "Unknown sticker",
38+
"10062": "Unknown interaction",
39+
"10063": "Unknown application command",
40+
"10065": "Unknown voice state",
41+
"10066": "Unknown application command permissions",
42+
"10067": "Unknown Stage Instance",
43+
"10068": "Unknown Guild Member Verification Form",
44+
"10069": "Unknown Guild Welcome Screen",
45+
"10070": "Unknown Guild Scheduled Event",
46+
"10071": "Unknown Guild Scheduled Event User",
47+
"10087": "Unknown Tag",
48+
"20001": "Bots cannot use this endpoint",
49+
"20002": "Only bots can use this endpoint",
50+
"20009": "Explicit content cannot be sent to the desired recipient(s)",
51+
"20012": "You are not authorized to perform this action on this application",
52+
"20016": "This action cannot be performed due to slowmode rate limit",
53+
"20018": "Only the owner of this account can perform this action",
54+
"20022": "This message cannot be edited due to announcement rate limits",
55+
"20024": "Under minimum age",
56+
"20028": "The channel you are writing has hit the write rate limit",
57+
"20029": "The write action you are performing on the server has hit the write rate limit",
58+
"20031": "Your Stage topic, server name, server description, or channel names contain words that are not allowed",
59+
"20035": "Guild premium subscription level too low",
60+
"30001": "Maximum number of guilds reached (100)",
61+
"30002": "Maximum number of friends reached (1000)",
62+
"30003": "Maximum number of pins reached for the channel (50)",
63+
"30004": "Maximum number of recipients reached (10)",
64+
"30005": "Maximum number of guild roles reached (250)",
65+
"30007": "Maximum number of webhooks reached (15)",
66+
"30008": "Maximum number of emojis reached",
67+
"30010": "Maximum number of reactions reached (20)",
68+
"30011": "Maximum number of group DMs reached (10)",
69+
"30013": "Maximum number of guild channels reached (500)",
70+
"30015": "Maximum number of attachments in a message reached (10)",
71+
"30016": "Maximum number of invites reached (1000)",
72+
"30018": "Maximum number of animated emojis reached",
73+
"30019": "Maximum number of server members reached",
74+
"30030": "Maximum number of server categories has been reached (5)",
75+
"30031": "Guild already has a template",
76+
"30032": "Maximum number of application commands reached",
77+
"30033": "Maximum number of thread participants has been reached (1000)",
78+
"30034": "Maximum number of daily application command creates has been reached (200)",
79+
"30035": "Maximum number of bans for non-guild members have been exceeded",
80+
"30037": "Maximum number of bans fetches has been reached",
81+
"30038": "Maximum number of uncompleted guild scheduled events reached (100)",
82+
"30039": "Maximum number of stickers reached",
83+
"30040": "Maximum number of prune requests has been reached. Try again later",
84+
"30042": "Maximum number of guild widget settings updates has been reached. Try again later",
85+
"30046": "Maximum number of edits to messages older than 1 hour reached. Try again later",
86+
"30047": "Maximum number of pinned threads in a forum channel has been reached",
87+
"30048": "Maximum number of tags in a forum channel has been reached",
88+
"30052": "Bitrate is too high for channel of this type",
89+
"30056": "Maximum number of premium emojis reached (25)",
90+
"30058": "Maximum number of webhooks per guild reached (1000)",
91+
"30060": "Maximum number of channel permission overwrites reached (1000)",
92+
"30061": "The channels for this guild are too large",
93+
"40001": "Unauthorized. Provide a valid token and try again",
94+
"40002": "You need to verify your account in order to perform this action",
95+
"40003": "You are opening direct messages too fast",
96+
"40004": "Send messages has been temporarily disabled",
97+
"40005": "Request entity too large. Try sending something smaller in size",
98+
"40006": "This feature has been temporarily disabled server-side",
99+
"40007": "The user is banned from this guild",
100+
"40012": "Connection has been revoked",
101+
"40032": "Target user is not connected to voice",
102+
"40033": "This message has already been crossposted",
103+
"40041": "An application command with that name already exists",
104+
"40043": "Application interaction failed to send",
105+
"40058": "Cannot send a message in a forum channel",
106+
"40060": "Interaction has already been acknowledged",
107+
"40061": "Tag names must be unique",
108+
"40062": "Service resource is being rate limited",
109+
"40066": "There are no tags available that can be set by non-moderators",
110+
"40067": "A tag is required to create a forum post in this channel",
111+
"40074": "An entitlement has already been granted for this resource",
112+
"50001": "Missing access",
113+
"50002": "Invalid account type",
114+
"50003": "Cannot execute action on a DM channel",
115+
"50004": "Guild widget disabled",
116+
"50005": "Cannot edit a message authored by another user",
117+
"50006": "Cannot send an empty message",
118+
"50007": "Cannot send messages to this user",
119+
"50008": "Cannot send messages in a non-text channel",
120+
"50009": "Channel verification level is too high for you to gain access",
121+
"50010": "OAuth2 application does not have a bot",
122+
"50011": "OAuth2 application limit reached",
123+
"50012": "Invalid OAuth2 state",
124+
"50013": "You lack permissions to perform that action",
125+
"50014": "Invalid authentication token provided",
126+
"50015": "Note was too long",
127+
"50016": "Provided too few or too many messages to delete. Must provide at least 2 and fewer than 100 messages to delete",
128+
"50017": "Invalid MFA Level",
129+
"50019": "A message can only be pinned to the channel it was sent in",
130+
"50020": "Invite code was either invalid or taken",
131+
"50021": "Cannot execute action on a system message",
132+
"50024": "Cannot execute action on this channel type",
133+
"50025": "Invalid OAuth2 access token provided",
134+
"50026": "Missing required OAuth2 scope",
135+
"50027": "Invalid webhook token provided",
136+
"50028": "Invalid role",
137+
"50033": "Invalid Recipient(s)",
138+
"50034": "A message provided was too old to bulk delete",
139+
"50035": "Invalid form body (returned for both application/json and multipart/form-data bodies), or invalid Content-Type provided",
140+
"50036": "An invite was accepted to a guild the application's bot is not in",
141+
"50039": "Invalid Activity Action",
142+
"50041": "Invalid API version provided",
143+
"50045": "File uploaded exceeds the maximum size",
144+
"50046": "Invalid file uploaded",
145+
"50054": "Cannot self-redeem this gift",
146+
"50055": "Invalid Guild",
147+
"50057": "Invalid SKU",
148+
"50067": "Invalid request origin",
149+
"50068": "Invalid message type",
150+
"50070": "Payment source required to redeem gift",
151+
"50073": "Cannot modify a system webhook",
152+
"50074": "Cannot delete a channel required for Community guilds",
153+
"50080": "Cannot edit stickers within a message",
154+
"50081": "Invalid sticker sent",
155+
"50083": "Tried to perform an operation on an archived thread, such as editing a message or adding a user to the thread",
156+
"50084": "Invalid thread notification settings",
157+
"50085": "before value is earlier than the thread creation date",
158+
"50086": "Community server channels must be text channels",
159+
"50091": "The entity type of the event is different from the entity you are trying to start the event for",
160+
"50095": "This server is not available in your location",
161+
"50097": "This server needs monetization enabled in order to perform this action",
162+
"50101": "This server needs more boosts to perform this action",
163+
"50109": "The request body contains invalid JSON.",
164+
"50131": "Owner cannot be pending member",
165+
"50132": "Ownership cannot be transferred to a bot user",
166+
"50138": "Failed to resize asset below the maximum size: 262144",
167+
"50144": "Cannot mix subscription and non subscription roles for an emoji",
168+
"50145": "Cannot convert between premium emoji and normal emoji",
169+
"50146": "Uploaded file not found.",
170+
"50159": "Voice messages do not support additional content.",
171+
"50160": "Voice messages must have a single audio attachment.",
172+
"50161": "Voice messages must have supporting metadata.",
173+
"50162": "Voice messages cannot be edited.",
174+
"50163": "Cannot delete guild subscription integration",
175+
"50173": "You cannot send voice messages in this channel.",
176+
"50178": "The user account must first be verified",
177+
"50600": "You do not have permission to send this sticker.",
178+
"60003": "Two factor is required for this operation",
179+
"80004": "No users with DiscordTag exist",
180+
"90001": "Reaction was blocked",
181+
"90002": "User cannot use burst reactions",
182+
"110001": "Application not yet available. Try again later",
183+
"130000": "API resource is currently overloaded. Try again a little later",
184+
"150006": "The Stage is already open",
185+
"160002": "Cannot reply without permission to read message history",
186+
"160004": "A thread has already been created for this message",
187+
"160005": "Thread is locked",
188+
"160006": "Maximum number of active threads reached",
189+
"160007": "Maximum number of active announcement threads reached",
190+
"170001": "Invalid JSON for uploaded Lottie file",
191+
"170002": "Uploaded Lotties cannot contain rasterized images such as PNG or JPEG",
192+
"170003": "Sticker maximum framerate exceeded",
193+
"170004": "Sticker frame count exceeds maximum of 1000 frames",
194+
"170005": "Lottie animation maximum dimensions exceeded",
195+
"170006": "Sticker frame rate is either too small or too large",
196+
"170007": "Sticker animation duration exceeds maximum of 5 seconds",
197+
"180000": "Cannot update a finished event",
198+
"180002": "Failed to create stage needed for stage event",
199+
"200000": "Message was blocked by automatic moderation",
200+
"200001": "Title was blocked by automatic moderation",
201+
"220001": "Webhooks posted to forum channels must have a thread_name or thread_id",
202+
"220002": "Webhooks posted to forum channels cannot have both a thread_name and thread_id",
203+
"220003": "Webhooks can only create threads in forum channels",
204+
"220004": "Webhook services cannot be used in forum channels",
205+
"240000": "Message blocked by harmful links filter",
206+
"350000": "Cannot enable onboarding, requirements are not met",
207+
"350001": "Cannot update onboarding while below requirements",
208+
}
209+
210+
"""
211+
In order to make the SLO more relevant, we want to ignore specific discord provided codes that
212+
can be returned when a user changes a configuration and breaks the alert.
213+
214+
Eventually we would like to surface these codes to the user so they can fix their configuration.
215+
"""
216+
DISCORD_USER_ERRORS = {
217+
"10001", # user deleted account
218+
"10002", # user deleted application
219+
"10003", # user deleted channel
220+
"10004", # user deleted guild
221+
"10005", # user deleted integration
222+
"10008", # user deleted message
223+
"10011", # user deleted role
224+
"10013", # user deleted account
225+
"10087", # user deleted tag
226+
"20009", # user's error message contains explicit content
227+
"20018", # user changed action permissions to owner-restricted
228+
"50001", # user changed bot's permissions
229+
"50007", # user is preventing direct messages from bot **direct messages not implemented yet
230+
"50009", # bot not added to channel yet
231+
"50013", # user changed bot's permissions for actions
232+
"50055", # user changed or deleted guild (would likely only hit 10003)
233+
"50083", # user archived thread (would likely only hit 10003)
234+
"50178", # user not verified yet
235+
"60003", # user added 2 factor not sure if this can happen with bot
236+
"80004", # user DiscordTag does not exist (could have been deleted or modified)
237+
"160002", # user removed bot's permission to reply to thread
238+
"160005", # user locked a thread
239+
"200000", # auto mod blocked because of message content (user must contact moderator)
240+
"240000", # auto mod blocked because message contained harmful link (user must contact moderator)
241+
}

src/sentry/shared_integrations/client/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ def _request(
275275
self.record_error(e)
276276
raise ApiError("Internal Error", url=full_url) from e
277277

278-
self.track_response_data(error_resp.status_code, e, extra=extra)
278+
self.track_response_data(error_resp.status_code, e, resp=error_resp, extra=extra)
279279
self.record_error(e)
280280
raise ApiError.from_response(error_resp, url=full_url) from e
281281

0 commit comments

Comments
 (0)