From eeec128bb037b5a1c42b9f70ebc8ee4a99fe1d04 Mon Sep 17 00:00:00 2001 From: Verslabs Date: Fri, 23 Oct 2026 00:10:46 +0100 Subject: [PATCH] Fix tickets not creating when the bot lacks Administrator The auto-created Tickets category denies @everyone ViewChannel but gave the bot no overwrite. Discord only lets a bot grant permissions it has in the parent category, so creating the ticket channel with the member's ViewChannel overwrite failed with Missing Permissions: the category was created but no ticket channel. The ticket channel had the same gap, so the bot also could not post its opening message. Give the bot an explicit overwrite on the category and ticket channel, and repair existing ticket categories that are missing it. Fixes #152 Co-authored-by: Claude --- src/services/ticket.js | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/services/ticket.js b/src/services/ticket.js index 158a364d1c..1f7be91256 100644 --- a/src/services/ticket.js +++ b/src/services/ticket.js @@ -21,6 +21,35 @@ const TICKET_DELETE_DELAY_MS = 3000; const TICKET_DELETE_DELAY_SECONDS = Math.floor(TICKET_DELETE_DELAY_MS / 1000); const TICKET_SERVICE = 'ticketService'; +// Ticket categories and channels deny @everyone ViewChannel, so the bot needs its own +// overwrite. Without one, Discord rejects the member overwrites on the ticket channel +// (a bot can only grant permissions it has in the parent) and the bot cannot post in it. +const BOT_TICKET_PERMISSIONS = [ + PermissionFlagsBits.ViewChannel, + PermissionFlagsBits.SendMessages, + PermissionFlagsBits.EmbedLinks, + PermissionFlagsBits.AttachFiles, + PermissionFlagsBits.ReadMessageHistory, +]; + +// Repairs "Tickets" categories created before the bot overwrite existed. +async function ensureBotCanAccessCategory(category, botMember) { + if (!category || !botMember) return; + if (category.permissionsFor(botMember)?.has(BOT_TICKET_PERMISSIONS)) return; + + try { + await category.permissionOverwrites.edit(botMember.id, { + ViewChannel: true, + SendMessages: true, + EmbedLinks: true, + AttachFiles: true, + ReadMessageHistory: true, + }); + } catch (error) { + logger.warn(`Could not grant bot access to ticket category ${category.id}: ${error.message}`); + } +} + function ticketUserError(message, userMessage, type = ErrorTypes.VALIDATION, context = {}) { throw createError(message, type, userMessage, { service: TICKET_SERVICE, ...context }); } @@ -112,8 +141,14 @@ export async function createTicket(guild, member, categoryId, reason = 'No reaso id: guild.id, deny: [PermissionFlagsBits.ViewChannel], }, + { + id: guild.members.me.id, + allow: BOT_TICKET_PERMISSIONS, + }, ], }); + } else { + await ensureBotCanAccessCategory(category, guild.members.me); } const ticketNumber = await getNextTicketNumber(guild.id); @@ -136,6 +171,10 @@ export async function createTicket(guild, member, categoryId, reason = 'No reaso id: guild.id, deny: [PermissionFlagsBits.ViewChannel], }, + { + id: guild.members.me.id, + allow: BOT_TICKET_PERMISSIONS, + }, { id: member.id, allow: [