> ## Documentation Index
> Fetch the complete documentation index at: https://docs.guilt.icu/llms.txt
> Use this file to discover all available pages before exploring further.

# alterself Exceptions: Error Classes and Error Codes

> Complete reference for alterself exceptions including HTTPError with Discord error codes, gateway SessionClosed codes, and command errors.

Every exception raised by alterself inherits from the base class `AlterselfError`, so you can catch all library-level errors with a single `except AlterselfError` clause or target specific failure modes precisely. Understanding which exception maps to which failure condition lets you write resilient bots that handle rate limits, closed sessions, failed commands, and captcha challenges without crashing.

***

## Exception Hierarchy

```text theme={null}
AlterselfError
├── HTTPError              - HTTP request failed (4xx, 5xx)
├── GatewayError           - WebSocket-level failure
│   └── SessionClosed      - Gateway connection closed
├── CommandError           - Command pipeline failure
│   ├── CheckFailed        - A check decorator returned falsy
│   ├── ConversionFailed   - Type converter raised an exception
│   ├── CommandNotFound    - No command matched the invocation
│   └── MissingArgument    - Required argument absent
└── CaptchaChallenge       - Discord requires a captcha
```

***

## HTTPError

`HTTPError` is raised whenever an HTTP request to the Discord REST API returns a `4xx` or `5xx` response. It carries three pieces of information: the HTTP status code, Discord's own error code, and a human-readable message from Discord's response body.

### Attributes

| Attribute | Type | Description |
| - | - | - |
| `status` | `int` | The HTTP response status code (e.g. `403`, `404`, `429`). |
| `code` | `int` | The Discord JSON error code from the response body (e.g. `50013`). `0` if Discord did not include one. |
| `text` | `str` | The human-readable error message from Discord's response body. |

```python theme={null}
from alterself import HTTPError

try:
    await bot.http.send_message(channel_id, content="hello")
except HTTPError as e:
    print(e.status)    # HTTP status code, e.g. 403
    print(e.code)      # Discord error code, e.g. 50013
    print(e.text)      # Discord error message, e.g. "Missing Permissions"
```

### Common Discord Error Codes

These are the Discord JSON error codes you are most likely to encounter during normal operation. The full list is available in the [Discord developer documentation](https://discord.com/developers/docs/topics/opcodes-and-status-codes#json).

| Code | Meaning |
| - | - |
| `10003` | Unknown channel: the channel ID does not exist or is not accessible. |
| `10004` | Unknown guild: the guild ID does not exist or your account is not in it. |
| `10008` | Unknown message: the message was deleted or never existed. |
| `50001` | Missing access: your account cannot see or interact with this resource. |
| `50013` | Missing permissions: your account lacks the required guild permission. |
| `50035` | Invalid form body: the request payload failed Discord's validation. Check required fields and value constraints. |

<Warning>
  HTTP status `429 Too Many Requests` is handled automatically by alterself's HTTP client. It reads the `Retry-After` header and retries the request after the cooldown expires. You will only see an `HTTPError` with `status=429` if the global rate limit is sustained for longer than alterself's configured retry budget.
</Warning>

***

## SessionClosed

`SessionClosed` is a subclass of `GatewayError` and is raised when the Discord gateway WebSocket connection closes with a close code. Some close codes are recoverable. alterself will automatically attempt to reconnect, but others are fatal and require you to address the underlying problem (such as an invalid token) before restarting.

### Attributes

| Attribute | Type | Description |
| - | - | - |
| `code` | `int` | The WebSocket close code sent by Discord. |

```python theme={null}
from alterself import SessionClosed

try:
    await bot.start()
except SessionClosed as e:
    print(e.code)   # WebSocket close code, e.g. 4004
```

### Fatal Close Codes

When alterself receives one of the following codes, it does **not** attempt to reconnect. The `SessionClosed` exception propagates out of `bot.start()` and your process should treat it as a terminal error.

| Code | Meaning |
| - | - |
| `4004` | Token invalid: the provided token was rejected by Discord. |
| `4010` | Invalid shard: the shard configuration sent to the gateway was invalid. |
| `4011` | Sharding required: the bot is in too many guilds and must use sharding. |
| `4012` | Invalid API version: the gateway API version is not supported. |
| `4013` | Invalid intents: the intents bitfield includes an unrecognised value. |
| `4014` | Disallowed intents: the intents bitfield requests a privileged intent not enabled in the developer portal. |

<Note>
  Non-fatal close codes (such as `4000` Unknown Error, `4001` Unknown Opcode, and `4009` Session Timed Out) trigger an automatic reconnect internally. You do not need to handle these yourself unless you want to log them.
</Note>

***

## CaptchaChallenge

`CaptchaChallenge` is raised when Discord responds to an HTTP request by requiring you to solve an hCaptcha challenge before the action can proceed. This occurs most often on account actions such as joining a guild, sending a friend request, or logging in from an unrecognised location.

### Attributes

| Attribute | Type | Description |
| - | - | - |
| `sitekey` | `str` | The hCaptcha site key required to render the challenge widget. |
| `rqdata` | `str` | Additional challenge data passed to the hCaptcha enterprise API for this specific request. |

```python theme={null}
from alterself import CaptchaChallenge

try:
    await bot.http.join_guild("invite")
except CaptchaChallenge as e:
    print(e.sitekey)   # hCaptcha site key
    print(e.rqdata)    # Additional challenge data
    # Pass these values to your captcha solver, then retry the request
    # with the resulting token via bot.http.submit_captcha(...)
```

<Warning>
  alterself does not bundle a captcha solver. Solving the challenge is your responsibility. Frequent `CaptchaChallenge` errors on common actions are a signal that Discord has flagged the account. Reducing request frequency and ensuring realistic behaviour patterns will help.
</Warning>

***

## CommandError

`CommandError` is the base class for all failures that occur within the command processing pipeline. You typically handle these in a global error handler registered with `@bot.on_command_error` rather than wrapping every individual command invocation in a try/except block.

### CheckFailed

`CheckFailed` is raised when a check predicate, a function decorated with `@commands.check`, returns a falsy value. It signals that the invoking user, channel, or context did not meet the conditions you defined.

By default, alterself silently ignores `CheckFailed` and does not send any message to the user. You only need to handle it explicitly if you want to send feedback or log the failed check.

```python theme={null}
from alterself import CheckFailed

@bot.on_command_error
async def on_error(ctx, error):
    if isinstance(error, CheckFailed):
        await ctx.reply("You don't have permission to use that command.")
```

### ConversionFailed

`ConversionFailed` is raised when an argument type converter encounters an error. For example, when a command expects an `int` but the user passes a word that cannot be parsed as one.

### CommandNotFound

`CommandNotFound` is raised when the prefix and command name were parsed successfully, but no registered command matches the name. You can use this to silently ignore unknown commands or to suggest alternatives.

### MissingArgument

`MissingArgument` is raised when a command handler declares a required parameter but the user's invocation did not supply a value for it.

```python theme={null}
@bot.on_command_error
async def on_error(ctx, error):
    if isinstance(error, CheckFailed):
        await ctx.reply("You lack the required permissions.")
    elif isinstance(error, ConversionFailed):
        await ctx.reply(f"Invalid value for argument: {error}")
    elif isinstance(error, MissingArgument):
        await ctx.reply(f"Missing required argument: {error}")
    elif isinstance(error, CommandNotFound):
        pass   # Silently ignore unknown commands
```

<Tip>
  Register a single `@bot.on_command_error` handler at the top level of your bot file to centralise error reporting. This keeps individual command functions clean and ensures you never miss an unhandled `CommandError`.
</Tip>
