---
title: "Exceptions — Tags for Laravel | Roundly"
description: "Every TagsException with its stable error code and HTTP status — plus how to present them through errorCode(), clientMessage() and status()."
url: https://roundly-consulting.com/open-source/docs/tags-for-laravel/exceptions
language: en
---

[All packages](https://roundly-consulting.com/open-source.md)

[Tags for Laravel](https://roundly-consulting.com/open-source/docs/tags-for-laravel.md)

# Exceptions

Every exception the package throws for a call it refuses extends TagsException (a RuntimeException). Present them through four stable methods rather than knowing each class: errorCode() — a snake\_case code, public API from 1.0; status() — the HTTP status for a reference in a request body; isNotFound() — the not-found family, which answers 404 when the reference was a path segment; clientMessage() — the translated text a client may see. Messages come from tags::messages in English and Slovak and never name a PHP class:

```php
use RoundlyConsulting\Tags\Exceptions\TagsException;

try {
    $concert->attachTags($request->input('labels', []), 'label');
} catch (TagsException $e) {
    return response()->json(
        ['message' => $e->clientMessage(), 'code' => $e->errorCode()],
        $e->status(),
    );
}
```

| Exception | errorCode() | status() | When |
| --- | --- | --- | --- |
| `UnknownTagTypeException` | `unknown_tag_type / type_required` | 404 / 422 | A type nobody defined (or one hidden from the caller); a string input with no type while there is no default type. |
| `TagNotFoundException` | `tag_not_found` | 422 (404 in the path) | A key, slug or name that matches no live tag the caller may use; a deleted tag. |
| `TagScopeMismatchException` | `tag_not_found` | 422 (404 in the path) | A tag of another scope — presents exactly like a missing one; getMessage() keeps the precise text for logs. |
| `DuplicateTagException` | `duplicate_tag` | 409 | A name or manual slug whose slug another tag of the type and scope holds — names the slug and the locale, and points to restore() when a deleted tag holds it. |
| `InvalidTagException` | `invalid_tag` | 422 | A blank, too long or unsluggable name, an unsupported or malformed locale, a bad colour, icon, description, slug or position, a manual slug on a free-form type, a scope on a global-only type, a change to type or owner. |
| `InvalidTagHierarchyException` | `invalid_hierarchy` | 422 | A cycle, a tree deeper than the type allows, a parent on a flat type, a deleted parent. |
| `TagHasChildrenException` | `tag_has_children` | 409 | A delete that would orphan live children — pass TagChildren::Reparent or Delete. |
| `TagLimitExceededException` | `tag_limit_exceeded` | 422 | A write that would leave a model with more tags of a type than allowed; nothing is written. |
| `TagTypeMismatchException` | `tag_type_mismatch` | 422 | A tag of one type used where another was asked for — a tagging call, a parent, a handle. |
| `TagTypeNotAllowedException` | `tag_type_not_allowed` | 422 | The type’s on() list or the model’s tagTypes() leaves the other out. |
| `UnknownMorphAliasException` | `unknown_alias` | 422 | An API scope or taggable reference the allow-lists do not hold — or a scope the caller may not use, which answers the same. |
| `InvalidTagTypeException` | `invalid_tag_type` | 500 | A type definition that cannot work (see Tag types). |
| `TagTypeAlreadyDefinedException` | `type_already_defined` | 500 | A second definition of one name, naming both definers. |
| `UnsavedTaggableException` | `unsaved_taggable` | 500 | Tagging a model that is not saved yet. |

- A missing key presents to clients exactly like a tag of another scope: clientMessage() is the generic “The tag does not exist.” while getMessage() keeps the key for your logs.
- Outside the family: InvalidTagsConfigurationException (configuration the package cannot work with, named by its key — it extends the toolkit’s exception, so catch it beside InvalidConfigurationException) and ReadOnlyTagsRelationException (a LogicException for a write through tags()).

## Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

[More ways to support, including crypto](https://roundly-consulting.com/support-us.md)

By donating, you agree to our [donation terms](https://roundly-consulting.com/donation-terms.md).

[Support our open source work (opens in a new tab)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Join us on Patreon (opens in a new tab)](https://www.patreon.com/cw/roundly)

## Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.

[Get a quote in 48 hours](https://roundly-consulting.com/contact.md) [Browse all packages](https://roundly-consulting.com/open-source/docs/tags-for-laravel.md)
