pallets/flask · error · KeyError

Tag ' ' is already registered.

Error message

Tag '{key}' is already registered.

What it means

TaggedJSONSerializer.register(tag_class) instantiates the tag, reads tag.key, and if key is truthy and already present in self.tags (and force=False), raises KeyError. This protects session/tag serialization from two tags claiming the same key, which would make encoded data ambiguous.

Solutions

  1. Choose a unique key for your custom JSONTag that does not collide with existing tags.
  2. Pass force=True to register() if you intentionally want to override an existing tag.
  3. Inspect app.session_interface.serializer.tags keys before registering to detect collisions.

Example fix

# before
class MyTag(JSONTag):
    key = 'list'   # collides with built-in
app.session_interface.serializer.register(MyTag)  # KeyError

# after
class MyTag(JSONTag):
    key = 'mylist'
app.session_interface.serializer.register(MyTag)
# or override: register(MyTag, force=True)
Defensive patterns

Strategy: validation

Validate before calling

def tag_key_available(serializer, key: str) -> bool:
    return key not in serializer.tags

Type guard

def is_unique_tag_key(serializer, key: str) -> bool:
    return key not in serializer.tags

Try / catch

try:
    serializer.register(MyTag)
except KeyError as e:
    if 'already registered' in str(e):
        serializer.register(MyTag, force=True)
    else:
        raise

Prevention

When it happens

Trigger: Registering a custom JSONTag whose key collides with a built-in tag key (e.g. ' di', 'list', 'tuple') or with another custom tag already registered, without passing force=True. The dict self.tags maps key->tag and a duplicate would overwrite silently.

Common situations: Extending session serialization with a custom tag and accidentally reusing an existing key. Loading a Flask extension that registers a tag also registered by another extension. Upgrading Flask where a new built-in tag key now collides with your custom one.

Related errors


AI-assisted analysis of pallets/flask@3596b1ab61 (2026-08-11). Data as JSON: /api/errors/e6e5f55392cffdaf. Report an issue: GitHub.

Appendix: source

Thrown at src/flask/json/tag.py:280

        """Register a new tag with this serializer.

        :param tag_class: tag class to register. Will be instantiated with this
            serializer instance.
        :param force: overwrite an existing tag. If false (default), a
            :exc:`KeyError` is raised.
        :param index: index to insert the new tag in the tag order. Useful when
            the new tag is a special case of an existing tag. If ``None``
            (default), the tag is appended to the end of the order.

        :raise KeyError: if the tag key is already registered and ``force`` is
            not true.
        """
        tag = tag_class(self)
        key = tag.key

        if key:
            if not force and key in self.tags:
                raise KeyError(f"Tag '{key}' is already registered.")

            self.tags[key] = tag

        if index is None:
            self.order.append(tag)
        else:
            self.order.insert(index, tag)

    def tag(self, value: t.Any) -> t.Any:
        """Convert a value to a tagged representation if necessary."""
        for tag in self.order:
            if tag.check(value):
                return tag.tag(value)

        return value

    def untag(self, value: dict[str, t.Any]) -> t.Any:
        """Convert a tagged representation back to the original type."""

View on GitHub (pinned to 3596b1ab61)