Skip to content

Commit ab7b7a5

Browse files
authored
Handle new Discord error codes and improve error messaging (#116)
* Handle new Discord error codes and i18n messages Add handling for additional Discord API error codes (30013: max channels; 160005: thread locked; 160006: max active threads; 160007: max active announcement threads) and return corresponding localized messages. Introduce a docsUrl variable to centralize the docs link and use a new MessageErrorMissingAccess message when access is denied or permissions cannot be determined. Update i18n message IDs to include max_channels, thread_locked, max_active_threads, max_active_announcement_threads, and missing_access. * Handle channel creation error before closing ticket When CreateGuildChannel fails, call cmd.HandleError(err) immediately and remove the duplicate call later. This ensures the original channel creation error is surfaced before attempting ticket cleanup (closing the ticket) and avoids handling the same error twice. No behavioral change to the subsequent REST error handling logic.
1 parent bf199b0 commit ab7b7a5

3 files changed

Lines changed: 45 additions & 31 deletions

File tree

bot/command/context/replyable.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -204,10 +204,13 @@ func (r *Replyable) buildErrorResponse(err error, eventId string, includeInviteL
204204
message = r.GetMessage(i18n.MessageErrorUnknownInteraction)
205205
} else if restError.ApiError.Code == 30007 { // Maximum number of webhooks reached
206206
message = r.GetMessage(i18n.MessageErrorMaxWebhooks)
207+
} else if restError.ApiError.Code == 30013 { // Maximum number of guild channels reached
208+
message = r.GetMessage(i18n.MessageErrorMaxChannels)
207209
} else if restError.ApiError.Code == 40060 { // Interaction has already been acknowledged
208210
message = r.GetMessage(i18n.MessageErrorInteractionAcknowledged)
209211
} else if restError.ApiError.Code == 50001 || restError.ApiError.Code == 50013 { // Missing permissions / Missing access
210212
interactionCtx, ok := r.ctx.(registry.InteractionContext)
213+
docsUrl := fmt.Sprintf("%s/miscellaneous/permissions-explained", config.Conf.Bot.DocsUrl)
211214
if ok {
212215
missingPermissions, err := findMissingPermissions(interactionCtx)
213216
if err == nil {
@@ -217,16 +220,16 @@ func (r *Replyable) buildErrorResponse(err error, eventId string, includeInviteL
217220
message += fmt.Sprintf("* `%s`\n", perm.String())
218221
}
219222

220-
message += "\n" + r.GetMessage(i18n.MessageErrorMissingPermissionsBody, fmt.Sprintf("%s/miscellaneous/permissions-explained", config.Conf.Bot.DocsUrl))
223+
message += "\n" + r.GetMessage(i18n.MessageErrorMissingPermissionsBody, docsUrl)
221224
} else {
222-
message = r.formatDiscordError(restError, eventId)
225+
message = r.GetMessage(i18n.MessageErrorMissingAccess, docsUrl)
223226
}
224227
} else {
225228
sentry.ErrorWithContext(err, r.ctx.ToErrorContext())
226-
message = r.formatDiscordError(restError, eventId)
229+
message = r.GetMessage(i18n.MessageErrorMissingAccess, docsUrl)
227230
}
228231
} else {
229-
message = r.formatDiscordError(restError, eventId)
232+
message = r.GetMessage(i18n.MessageErrorMissingAccess, docsUrl)
230233
}
231234
} else if restError.ApiError.Code == 50035 { // Invalid Form Body
232235
// Check for specific form validation errors
@@ -248,6 +251,12 @@ func (r *Replyable) buildErrorResponse(err error, eventId string, includeInviteL
248251
message = r.GetMessage(i18n.MessageErrorInvalidForm) + "\n\n" +
249252
r.formatDiscordError(restError, eventId)
250253
}
254+
} else if restError.ApiError.Code == 160005 { // Thread is locked
255+
message = r.GetMessage(i18n.MessageErrorThreadLocked)
256+
} else if restError.ApiError.Code == 160006 { // Maximum number of active threads reached
257+
message = r.GetMessage(i18n.MessageErrorMaxActiveThreads)
258+
} else if restError.ApiError.Code == 160007 { // Maximum number of active announcement threads reached
259+
message = r.GetMessage(i18n.MessageErrorMaxActiveAnnouncementThreads)
251260
} else if restError.StatusCode == http.StatusTooManyRequests {
252261
// Rate limit error - parse raw response to extract retry_after and global flag
253262
var rateLimit rateLimitResponse

bot/logic/open.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -369,13 +369,13 @@ func OpenTicket(ctx context.Context, cmd registry.InteractionContext, panel *dat
369369
reasonCtx := request.WithAuditReason(context.Background(), auditReason)
370370
tmp, err := cmd.Worker().CreateGuildChannel(reasonCtx, cmd.GuildId(), data)
371371
if err != nil { // Bot likely doesn't have permission
372+
cmd.HandleError(err)
373+
372374
// To prevent tickets getting in a glitched state, we should mark it as closed (or delete it completely?)
373375
if err := dbclient.Client.Tickets.Close(ctx, ticketId, cmd.GuildId()); err != nil {
374376
cmd.HandleError(err)
375377
}
376378

377-
cmd.HandleError(err)
378-
379379
var restError request.RestError
380380
if errors.As(err, &restError) && restError.ApiError.FirstErrorCode() == "CHANNEL_PARENT_MAX_CHANNELS" {
381381
canRefresh, err := redis.TakeChannelRefetchToken(ctx, cmd.GuildId())

i18n/messages.go

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -290,31 +290,36 @@ var (
290290
MessageButtonGuildOnly MessageId = "button.guild_only"
291291
MessageButtonDMOnly MessageId = "button.dms_only"
292292

293-
MessageErrorUnknownChannel MessageId = "errors.unknown_channel"
294-
MessageErrorUnknownGuild MessageId = "errors.unknown_guild"
295-
MessageErrorUnknownMember MessageId = "errors.unknown_member"
296-
MessageErrorUnknownMessage MessageId = "errors.unknown_message"
297-
MessageErrorUnknownUser MessageId = "errors.unknown_user"
298-
MessageErrorUnknownRole MessageId = "errors.unknown_role"
299-
MessageErrorUnknownCategory MessageId = "errors.unknown_category"
300-
MessageErrorUnknownInteraction MessageId = "errors.unknown_interaction"
301-
MessageErrorMaxWebhooks MessageId = "errors.max_webhooks"
302-
MessageErrorInteractionAcknowledged MessageId = "errors.interaction_acknowledged"
303-
MessageErrorMissingPermissionsTitle MessageId = "errors.missing_permissions.title"
304-
MessageErrorMissingPermissionsBody MessageId = "errors.missing_permissions.body"
305-
MessageErrorInvalidLength MessageId = "errors.invalid_length"
306-
MessageErrorRequiredField MessageId = "errors.required_field"
307-
MessageErrorInvalidChannelType MessageId = "errors.invalid_channel_type"
308-
MessageErrorInvalidCategory MessageId = "errors.invalid_category"
309-
MessageErrorInvalidId MessageId = "errors.invalid_id"
310-
MessageErrorInvalidCharacters MessageId = "errors.invalid_characters"
311-
MessageErrorInvalidChoice MessageId = "errors.invalid_choice"
312-
MessageErrorInvalidForm MessageId = "errors.invalid_form"
313-
MessageErrorTimeout MessageId = "errors.timed_out"
314-
MessageErrorRateLimited MessageId = "errors.rate_limited"
315-
MessageErrorRateLimitedGlobal MessageId = "errors.rate_limited_global"
316-
MessageErrorGeneral MessageId = "errors.general"
317-
MessageErrorId MessageId = "errors.error_id"
293+
MessageErrorUnknownChannel MessageId = "errors.unknown_channel"
294+
MessageErrorUnknownGuild MessageId = "errors.unknown_guild"
295+
MessageErrorUnknownMember MessageId = "errors.unknown_member"
296+
MessageErrorUnknownMessage MessageId = "errors.unknown_message"
297+
MessageErrorUnknownUser MessageId = "errors.unknown_user"
298+
MessageErrorUnknownRole MessageId = "errors.unknown_role"
299+
MessageErrorUnknownCategory MessageId = "errors.unknown_category"
300+
MessageErrorUnknownInteraction MessageId = "errors.unknown_interaction"
301+
MessageErrorMaxWebhooks MessageId = "errors.max_webhooks"
302+
MessageErrorMaxChannels MessageId = "errors.max_channels"
303+
MessageErrorInteractionAcknowledged MessageId = "errors.interaction_acknowledged"
304+
MessageErrorMissingPermissionsTitle MessageId = "errors.missing_permissions.title"
305+
MessageErrorMissingPermissionsBody MessageId = "errors.missing_permissions.body"
306+
MessageErrorMissingAccess MessageId = "errors.missing_access"
307+
MessageErrorInvalidLength MessageId = "errors.invalid_length"
308+
MessageErrorRequiredField MessageId = "errors.required_field"
309+
MessageErrorInvalidChannelType MessageId = "errors.invalid_channel_type"
310+
MessageErrorInvalidCategory MessageId = "errors.invalid_category"
311+
MessageErrorInvalidId MessageId = "errors.invalid_id"
312+
MessageErrorInvalidCharacters MessageId = "errors.invalid_characters"
313+
MessageErrorInvalidChoice MessageId = "errors.invalid_choice"
314+
MessageErrorInvalidForm MessageId = "errors.invalid_form"
315+
MessageErrorThreadLocked MessageId = "errors.thread_locked"
316+
MessageErrorMaxActiveThreads MessageId = "errors.max_active_threads"
317+
MessageErrorMaxActiveAnnouncementThreads MessageId = "errors.max_active_announcement_threads"
318+
MessageErrorTimeout MessageId = "errors.timed_out"
319+
MessageErrorRateLimited MessageId = "errors.rate_limited"
320+
MessageErrorRateLimitedGlobal MessageId = "errors.rate_limited_global"
321+
MessageErrorGeneral MessageId = "errors.general"
322+
MessageErrorId MessageId = "errors.error_id"
318323

319324
HelpAdmin MessageId = "help.admin"
320325
HelpAdminDebug MessageId = "help.admin.debug"

0 commit comments

Comments
 (0)