tickets_plus.cogs.errors
A cog that handles errors from app commands globally.
We use this cog to handle errors from app commands globally. This is to actually handle and respond to errors. It's nice to not leave the user confused.
Typical usage example:
from tickets_plus import bot bot_instance = bot.TicketsPlusBot(...) await bot_instance.load_extension("tickets_plus.cogs.errors")
1"""A cog that handles errors from app commands globally. 2 3We use this cog to handle errors from app commands globally. 4This is to actually handle and respond to errors. 5It's nice to not leave the user confused. 6 7Typical usage example: 8 ```py 9 from tickets_plus import bot 10 bot_instance = bot.TicketsPlusBot(...) 11 await bot_instance.load_extension("tickets_plus.cogs.errors") 12 ``` 13""" 14# License: EPL-2.0 15# SPDX-License-Identifier: EPL-2.0 16# Copyright (c) 2021-present The Tickets+ Contributors 17# This Source Code may also be made available under the following 18# Secondary Licenses when the conditions for such availability set forth 19# in the Eclipse Public License, v. 2.0 are satisfied: GPL-3.0-only OR 20# If later approved by the Initial Contributor, GPL-3.0-or-later. 21 22import logging 23 24import discord 25from discord import app_commands, utils 26from discord.ext import commands 27from sqlalchemy import exc 28 29from tickets_plus import bot 30from tickets_plus.ext import exceptions 31 32 33class ErrorHandling(commands.Cog, name="AppCommandErrorHandler"): 34 """Error handling for Tickets+. 35 36 This cog is used to handle errors from app commands globally. 37 This is to actually handle and respond to errors. 38 39 Attributes: 40 old_error_handler: The old error handler. 41 This is used to restore the old error handler. 42 """ 43 44 def __init__(self, bot_instance: bot.TicketsPlusBot) -> None: 45 """Initialises the cog instance. 46 47 We store some attributes here for later use. 48 49 Args: 50 bot_instance: The bot instance. 51 """ 52 self._bt = bot_instance 53 logging.info("Loaded %s", self.__class__.__name__) 54 55 async def cog_load(self) -> None: 56 """Adds the error handler to the bot. 57 58 Should not be called manually. 59 """ 60 tree = self._bt.tree 61 self.old_error_handler = tree.on_error 62 tree.on_error = self.on_app_command_error 63 logging.info("Error handling ready.") 64 65 async def cog_unload(self) -> None: 66 """Removes the error handler from the bot. 67 68 Should not be called manually. 69 """ 70 tree = self._bt.tree 71 tree.on_error = self.old_error_handler 72 logging.info("Error handling unloaded.") 73 74 @staticmethod 75 async def on_app_command_error(ctx: discord.Interaction, error: app_commands.AppCommandError) -> None: 76 """Handles errors from app commands globally. 77 78 This function is automatically called when an error is raised 79 from an app command. 80 This is used to handle and respond to errors. 81 To not leave the user confused. 82 83 Args: 84 ctx: The interaction that raised the error. 85 error: The error that was raised. 86 """ 87 if not ctx.response.is_done(): 88 await ctx.response.defer(ephemeral=True) 89 if isinstance(ctx.command, app_commands.Command): 90 # Splitting because, we don't want AttributeError 91 if hasattr(ctx.command, "on_error"): 92 # Same as above 93 if ctx.command.on_error is not None: 94 return 95 96 emd = discord.Embed( 97 title="Tickets+ Error: 500 - Internal Server Error", 98 description=("An unexpected internal error occurred.\n" 99 "Please report this error to the bot " 100 "developers. You can get the link to " 101 "GitHub and support server by using " 102 "the /version command."), 103 color=discord.Color.red(), 104 timestamp=utils.utcnow(), 105 ) 106 107 if isinstance(error, app_commands.CommandNotFound): 108 emd.title = "Tickets+ Error: 404 - Command Not Found" 109 emd.description = "The command you tried to use does not exist." 110 emd.set_footer(text="If this error persists, please report it.") 111 await ctx.followup.send(embed=emd, ephemeral=True) 112 return 113 114 if isinstance(error, app_commands.CheckFailure): 115 if isinstance(error, app_commands.BotMissingPermissions): 116 emd.title = "Tickets+ Error: 503 - Bot Missing Permissions" 117 emd.description = ("The bot is missing permissions required" 118 " to run this command.\n" 119 "Please ask a server administrator to grant the bot the " 120 "following permissions:\n" 121 f"{chr(92).join(error.missing_permissions)}") 122 emd.set_footer(text="If you are sure the bot has the " 123 "required permissions, please report this.") 124 await ctx.followup.send(embed=emd, ephemeral=True) 125 return 126 127 if isinstance(error, app_commands.NoPrivateMessage): 128 emd.title = "Tickets+ Error: 405 - DMs Not Allowed" 129 emd.description = "This command cannot be used in DMs." 130 emd.set_footer(text="Please use this command in a server.") 131 await ctx.followup.send(embed=emd, ephemeral=True) 132 return 133 134 if isinstance(error, app_commands.CommandOnCooldown): 135 emd.title = "Tickets+ Error: 429 - Command On Cooldown" 136 emd.description = ("This command is on cooldown.\n" 137 f"Please try again in {error.retry_after} seconds.") 138 emd.set_footer(text="Thank you for using Tickets+!") 139 await ctx.followup.send(embed=emd, ephemeral=True) 140 return 141 142 emd.title = "Tickets+ Error: 403 - Forbidden" 143 emd.description = "You do not have permission to use this command." 144 emd.set_footer(text=f"Error type: {type(error).__name__}") 145 await ctx.followup.send(embed=emd, ephemeral=True) 146 return 147 148 if isinstance(error, exceptions.TicketsPlusCommandError): 149 emd.title = "Tickets+ Error: 400 - Bad Request" 150 emd.description = str(error) 151 emd.set_footer(text=f"Error type: {type(error).__name__}") 152 await ctx.followup.send(embed=emd, ephemeral=True) 153 return # We don't want to log this error. 154 155 if isinstance(error, app_commands.CommandInvokeError): 156 underlying_error = error.original 157 158 if isinstance(underlying_error, exc.SQLAlchemyError): 159 logging.error("An error occurred while accessing the database:", exc_info=underlying_error) 160 emd.title = "Tickets+ Error: 500 - Database Error" 161 emd.description = ("An error occurred while accessing the database.\n" 162 "Please try again later. If this error persists, " 163 "please report it.\n" 164 "You can get the link to GitHub and support server by " 165 "using the /version command.") 166 emd.set_footer(text=f"Error type: {type(underlying_error)}") 167 await ctx.followup.send(embed=emd, ephemeral=True) 168 return 169 170 logging.error("An unhandled error occurred while executing a command:", exc_info=error) 171 emd.set_footer(text=f"Error type: {type(error).__name__}") 172 await ctx.followup.send(embed=emd, ephemeral=True) 173 174 175async def setup(bot_instance: bot.TicketsPlusBot) -> None: 176 """Sets up the error handler. 177 178 This function is called when the cog is loaded. 179 It is used to add the cog to the bot. 180 181 Args: 182 bot_instance: The bot instance. 183 """ 184 await bot_instance.add_cog(ErrorHandling(bot_instance))
34class ErrorHandling(commands.Cog, name="AppCommandErrorHandler"): 35 """Error handling for Tickets+. 36 37 This cog is used to handle errors from app commands globally. 38 This is to actually handle and respond to errors. 39 40 Attributes: 41 old_error_handler: The old error handler. 42 This is used to restore the old error handler. 43 """ 44 45 def __init__(self, bot_instance: bot.TicketsPlusBot) -> None: 46 """Initialises the cog instance. 47 48 We store some attributes here for later use. 49 50 Args: 51 bot_instance: The bot instance. 52 """ 53 self._bt = bot_instance 54 logging.info("Loaded %s", self.__class__.__name__) 55 56 async def cog_load(self) -> None: 57 """Adds the error handler to the bot. 58 59 Should not be called manually. 60 """ 61 tree = self._bt.tree 62 self.old_error_handler = tree.on_error 63 tree.on_error = self.on_app_command_error 64 logging.info("Error handling ready.") 65 66 async def cog_unload(self) -> None: 67 """Removes the error handler from the bot. 68 69 Should not be called manually. 70 """ 71 tree = self._bt.tree 72 tree.on_error = self.old_error_handler 73 logging.info("Error handling unloaded.") 74 75 @staticmethod 76 async def on_app_command_error(ctx: discord.Interaction, error: app_commands.AppCommandError) -> None: 77 """Handles errors from app commands globally. 78 79 This function is automatically called when an error is raised 80 from an app command. 81 This is used to handle and respond to errors. 82 To not leave the user confused. 83 84 Args: 85 ctx: The interaction that raised the error. 86 error: The error that was raised. 87 """ 88 if not ctx.response.is_done(): 89 await ctx.response.defer(ephemeral=True) 90 if isinstance(ctx.command, app_commands.Command): 91 # Splitting because, we don't want AttributeError 92 if hasattr(ctx.command, "on_error"): 93 # Same as above 94 if ctx.command.on_error is not None: 95 return 96 97 emd = discord.Embed( 98 title="Tickets+ Error: 500 - Internal Server Error", 99 description=("An unexpected internal error occurred.\n" 100 "Please report this error to the bot " 101 "developers. You can get the link to " 102 "GitHub and support server by using " 103 "the /version command."), 104 color=discord.Color.red(), 105 timestamp=utils.utcnow(), 106 ) 107 108 if isinstance(error, app_commands.CommandNotFound): 109 emd.title = "Tickets+ Error: 404 - Command Not Found" 110 emd.description = "The command you tried to use does not exist." 111 emd.set_footer(text="If this error persists, please report it.") 112 await ctx.followup.send(embed=emd, ephemeral=True) 113 return 114 115 if isinstance(error, app_commands.CheckFailure): 116 if isinstance(error, app_commands.BotMissingPermissions): 117 emd.title = "Tickets+ Error: 503 - Bot Missing Permissions" 118 emd.description = ("The bot is missing permissions required" 119 " to run this command.\n" 120 "Please ask a server administrator to grant the bot the " 121 "following permissions:\n" 122 f"{chr(92).join(error.missing_permissions)}") 123 emd.set_footer(text="If you are sure the bot has the " 124 "required permissions, please report this.") 125 await ctx.followup.send(embed=emd, ephemeral=True) 126 return 127 128 if isinstance(error, app_commands.NoPrivateMessage): 129 emd.title = "Tickets+ Error: 405 - DMs Not Allowed" 130 emd.description = "This command cannot be used in DMs." 131 emd.set_footer(text="Please use this command in a server.") 132 await ctx.followup.send(embed=emd, ephemeral=True) 133 return 134 135 if isinstance(error, app_commands.CommandOnCooldown): 136 emd.title = "Tickets+ Error: 429 - Command On Cooldown" 137 emd.description = ("This command is on cooldown.\n" 138 f"Please try again in {error.retry_after} seconds.") 139 emd.set_footer(text="Thank you for using Tickets+!") 140 await ctx.followup.send(embed=emd, ephemeral=True) 141 return 142 143 emd.title = "Tickets+ Error: 403 - Forbidden" 144 emd.description = "You do not have permission to use this command." 145 emd.set_footer(text=f"Error type: {type(error).__name__}") 146 await ctx.followup.send(embed=emd, ephemeral=True) 147 return 148 149 if isinstance(error, exceptions.TicketsPlusCommandError): 150 emd.title = "Tickets+ Error: 400 - Bad Request" 151 emd.description = str(error) 152 emd.set_footer(text=f"Error type: {type(error).__name__}") 153 await ctx.followup.send(embed=emd, ephemeral=True) 154 return # We don't want to log this error. 155 156 if isinstance(error, app_commands.CommandInvokeError): 157 underlying_error = error.original 158 159 if isinstance(underlying_error, exc.SQLAlchemyError): 160 logging.error("An error occurred while accessing the database:", exc_info=underlying_error) 161 emd.title = "Tickets+ Error: 500 - Database Error" 162 emd.description = ("An error occurred while accessing the database.\n" 163 "Please try again later. If this error persists, " 164 "please report it.\n" 165 "You can get the link to GitHub and support server by " 166 "using the /version command.") 167 emd.set_footer(text=f"Error type: {type(underlying_error)}") 168 await ctx.followup.send(embed=emd, ephemeral=True) 169 return 170 171 logging.error("An unhandled error occurred while executing a command:", exc_info=error) 172 emd.set_footer(text=f"Error type: {type(error).__name__}") 173 await ctx.followup.send(embed=emd, ephemeral=True)
Error handling for Tickets+.
This cog is used to handle errors from app commands globally. This is to actually handle and respond to errors.
Attributes:
- old_error_handler: The old error handler. This is used to restore the old error handler.
45 def __init__(self, bot_instance: bot.TicketsPlusBot) -> None: 46 """Initialises the cog instance. 47 48 We store some attributes here for later use. 49 50 Args: 51 bot_instance: The bot instance. 52 """ 53 self._bt = bot_instance 54 logging.info("Loaded %s", self.__class__.__name__)
Initialises the cog instance.
We store some attributes here for later use.
Arguments:
- bot_instance: The bot instance.
56 async def cog_load(self) -> None: 57 """Adds the error handler to the bot. 58 59 Should not be called manually. 60 """ 61 tree = self._bt.tree 62 self.old_error_handler = tree.on_error 63 tree.on_error = self.on_app_command_error 64 logging.info("Error handling ready.")
Adds the error handler to the bot.
Should not be called manually.
66 async def cog_unload(self) -> None: 67 """Removes the error handler from the bot. 68 69 Should not be called manually. 70 """ 71 tree = self._bt.tree 72 tree.on_error = self.old_error_handler 73 logging.info("Error handling unloaded.")
Removes the error handler from the bot.
Should not be called manually.
75 @staticmethod 76 async def on_app_command_error(ctx: discord.Interaction, error: app_commands.AppCommandError) -> None: 77 """Handles errors from app commands globally. 78 79 This function is automatically called when an error is raised 80 from an app command. 81 This is used to handle and respond to errors. 82 To not leave the user confused. 83 84 Args: 85 ctx: The interaction that raised the error. 86 error: The error that was raised. 87 """ 88 if not ctx.response.is_done(): 89 await ctx.response.defer(ephemeral=True) 90 if isinstance(ctx.command, app_commands.Command): 91 # Splitting because, we don't want AttributeError 92 if hasattr(ctx.command, "on_error"): 93 # Same as above 94 if ctx.command.on_error is not None: 95 return 96 97 emd = discord.Embed( 98 title="Tickets+ Error: 500 - Internal Server Error", 99 description=("An unexpected internal error occurred.\n" 100 "Please report this error to the bot " 101 "developers. You can get the link to " 102 "GitHub and support server by using " 103 "the /version command."), 104 color=discord.Color.red(), 105 timestamp=utils.utcnow(), 106 ) 107 108 if isinstance(error, app_commands.CommandNotFound): 109 emd.title = "Tickets+ Error: 404 - Command Not Found" 110 emd.description = "The command you tried to use does not exist." 111 emd.set_footer(text="If this error persists, please report it.") 112 await ctx.followup.send(embed=emd, ephemeral=True) 113 return 114 115 if isinstance(error, app_commands.CheckFailure): 116 if isinstance(error, app_commands.BotMissingPermissions): 117 emd.title = "Tickets+ Error: 503 - Bot Missing Permissions" 118 emd.description = ("The bot is missing permissions required" 119 " to run this command.\n" 120 "Please ask a server administrator to grant the bot the " 121 "following permissions:\n" 122 f"{chr(92).join(error.missing_permissions)}") 123 emd.set_footer(text="If you are sure the bot has the " 124 "required permissions, please report this.") 125 await ctx.followup.send(embed=emd, ephemeral=True) 126 return 127 128 if isinstance(error, app_commands.NoPrivateMessage): 129 emd.title = "Tickets+ Error: 405 - DMs Not Allowed" 130 emd.description = "This command cannot be used in DMs." 131 emd.set_footer(text="Please use this command in a server.") 132 await ctx.followup.send(embed=emd, ephemeral=True) 133 return 134 135 if isinstance(error, app_commands.CommandOnCooldown): 136 emd.title = "Tickets+ Error: 429 - Command On Cooldown" 137 emd.description = ("This command is on cooldown.\n" 138 f"Please try again in {error.retry_after} seconds.") 139 emd.set_footer(text="Thank you for using Tickets+!") 140 await ctx.followup.send(embed=emd, ephemeral=True) 141 return 142 143 emd.title = "Tickets+ Error: 403 - Forbidden" 144 emd.description = "You do not have permission to use this command." 145 emd.set_footer(text=f"Error type: {type(error).__name__}") 146 await ctx.followup.send(embed=emd, ephemeral=True) 147 return 148 149 if isinstance(error, exceptions.TicketsPlusCommandError): 150 emd.title = "Tickets+ Error: 400 - Bad Request" 151 emd.description = str(error) 152 emd.set_footer(text=f"Error type: {type(error).__name__}") 153 await ctx.followup.send(embed=emd, ephemeral=True) 154 return # We don't want to log this error. 155 156 if isinstance(error, app_commands.CommandInvokeError): 157 underlying_error = error.original 158 159 if isinstance(underlying_error, exc.SQLAlchemyError): 160 logging.error("An error occurred while accessing the database:", exc_info=underlying_error) 161 emd.title = "Tickets+ Error: 500 - Database Error" 162 emd.description = ("An error occurred while accessing the database.\n" 163 "Please try again later. If this error persists, " 164 "please report it.\n" 165 "You can get the link to GitHub and support server by " 166 "using the /version command.") 167 emd.set_footer(text=f"Error type: {type(underlying_error)}") 168 await ctx.followup.send(embed=emd, ephemeral=True) 169 return 170 171 logging.error("An unhandled error occurred while executing a command:", exc_info=error) 172 emd.set_footer(text=f"Error type: {type(error).__name__}") 173 await ctx.followup.send(embed=emd, ephemeral=True)
Handles errors from app commands globally.
This function is automatically called when an error is raised from an app command. This is used to handle and respond to errors. To not leave the user confused.
Arguments:
- ctx: The interaction that raised the error.
- error: The error that was raised.
176async def setup(bot_instance: bot.TicketsPlusBot) -> None: 177 """Sets up the error handler. 178 179 This function is called when the cog is loaded. 180 It is used to add the cog to the bot. 181 182 Args: 183 bot_instance: The bot instance. 184 """ 185 await bot_instance.add_cog(ErrorHandling(bot_instance))
Sets up the error handler.
This function is called when the cog is loaded. It is used to add the cog to the bot.
Arguments:
- bot_instance: The bot instance.