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

# Testing and debugging

> Fix creation errors, understand caching, and avoid script injection.

# Testing and debugging

> Fix creation errors, understand caching, and avoid script injection.

## Debugging loop

<Steps>
  <Step title="Preview with sample input">
    ```bash theme={null} theme={null}
    ;cc preview mycommand @wanderer some text
    ```

    Preview runs the whole template engine but performs no moderation, economy, or database writes — so it is safe to run repeatedly while you iterate.
  </Step>

  <Step title="Check what is actually stored">
    ```bash theme={null} theme={null}
    ;cc show mycommand
    ```

    Confirms the saved script, the argument schema raze parsed out of your definition, and which permissions its actions require.
  </Step>

  <Step title="Check who can reach it">
    ```bash theme={null} theme={null}
    ;cc restrictions mycommand
    ```
  </Step>

  <Step title="Fix and re-save">
    `;cc set` on an existing name overwrites it and keeps a revision, so you can iterate freely.
  </Step>
</Steps>

***

## Creation errors

<AccordionGroup>
  <Accordion title="missing separator" icon="minus">
    Add a standalone `--`, `=>`, or `->` between the definition and the response. It must have whitespace around it.
  </Accordion>

  <Accordion title="already a command name" icon="ban">
    The name collides with a built-in raze command or with the reserved names `cc`, `customcommand`, `customcommands`. Pick another.
  </Accordion>

  <Accordion title="invalid name" icon="font">
    Names allow only lowercase letters, digits, `_`, and `-`, up to 32 characters.
  </Accordion>

  <Accordion title="invalid argument declaration" icon="brackets-curly">
    Use `(name)`, `[name]`, `(name...)`, or `[name...]`. Mismatched brackets such as `<member]` are rejected, and names must start with a letter.
  </Accordion>

  <Accordion title="cannot follow a rest argument" icon="arrow-right-to-line">
    A rest argument swallows the remainder of the input, so it has to be the last declaration.
  </Accordion>

  <Accordion title="needs a permission which you don't have" icon="lock">
    The script contains an [action](/server-config/custom-commands/actions) and you don't hold the Discord permission it maps to. You cannot create a command that does more than you can.
  </Accordion>

  <Accordion title="tier limit reached" icon="gauge-high">
    You've hit your [tier's cap](/server-config/custom-commands/overview#limits-by-tier) on saved commands. Delete one, or upgrade with `;upgrade`.
  </Accordion>
</AccordionGroup>

***

## Runtime behaviour to expect

| Symptom                                       | Cause                                                                                                                                                    |
| :-------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Missing required argument: (name)`           | A `(required)` argument was left out.                                                                                                                    |
| The command replies with something went wrong | The script raised while rendering. Simplify with `;cc preview` until you find the tag at fault.                                                          |
| An action tag shows up as literal text        | The operation name isn't recognised, so nothing was executed. Check the spelling against the [action reference](/server-config/custom-commands/actions). |
| An action produced no effect and no error     | The target was immune under your moderation settings — those are skipped silently.                                                                       |
| A short note appears under the reply          | Action failures report themselves as a small `-#` line, e.g. an unresolvable target or an insufficient balance.                                          |
| Old paginated messages stop navigating        | Page registrations are swept after 48 hours. Run the command again.                                                                                      |

***

## Caching

Custom commands are cached in memory for **30 seconds** per server.

* **Editing through `;cc`** — `set`, `remove`, `enable`, `disable`, `allow`, `unallow`, `deny`, `undeny`, `requireperm`, and `restrictions clear` all clear the cache immediately, so your change is live at once.
* **Editing the database directly** — wait up to 30 seconds, or restart the bot.

***

## User input is inert

Everything a member types is neutralised before it reaches the script: braces in argument values are converted to lookalike characters that no tag pattern matches. The same applies to any placeholder whose value is user-controlled text — usernames, nicknames, role names, channel names and topics.

```bash theme={null} theme={null}
;cc set shout (message...) -- Shout: {message}
```

```bash theme={null} theme={null}
;shout {db.set:secrets:key:value}
```

> Shout: ❴db.set:secrets:key:value❵

Nothing is written, no action fires, and no output directive is smuggled in. The text is echoed with the braces visibly replaced.

<Note>
  Output directives are read from the saved script *before* substitution, so `{delete}` or `{silent}` typed by an invoker can never take effect either.
</Note>

### Still worth doing

<CardGroup cols={2}>
  <Card title="Restrict the powerful ones" icon="lock">
    A command that bans or writes to the database should still be limited to trusted roles with an [allow list](/server-config/custom-commands/restrictions).
  </Card>

  <Card title="Watch the allow-list bypass" icon="key">
    A user or role allow entry skips the action permission check. Add someone deliberately, not for convenience.
  </Card>

  <Card title="Mind self-assign roles" icon="user-tag">
    A top-level `{add_role:}` applies to whoever runs the command. Only put roles there that anyone reaching the command should be able to hold.
  </Card>

  <Card title="Preview first" icon="eye">
    `;cc preview` renders the whole script without performing any action, write, or delivery side effect.
  </Card>
</CardGroup>
