pallets/flask · error · KeyError
Tag '{key}' is already registered.
Error message
Tag '{key}' is already registered. What it means
Raised by `TaggedJSONSerializer.register()` in src/flask/json/tag.py, the serializer Flask uses to encode non-JSON types (tuples, bytes, datetimes, Markup, UUID) in the session cookie. Each JSONTag subclass declares a unique `key` (like ' t' or ' b'); registering a second tag class with a key already in `self.tags` raises KeyError unless `force=True` is passed, preventing one tag from silently shadowing another and corrupting session round-trips.
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 6a2f545bfd)
Solutions
- Pick a unique `key` for your JSONTag subclass that doesn't collide with built-ins (' d', ' t', ' u', ' m', ' b', ' di', ' ti') or your other tags.
- If intentionally replacing an existing tag, pass `force=True`: `serializer.register(MyTag, force=True, index=0)`.
- Guard registration so it runs once (module-level flag, or check `key in serializer.tags` before registering) when using an app factory.
Example fix
# before
class TagOrderedDict(JSONTag):
key = " t" # collides with built-in TagTuple
serializer.register(TagOrderedDict)
# after
class TagOrderedDict(JSONTag):
key = " od"
if " od" not in serializer.tags:
serializer.register(TagOrderedDict, index=0) Defensive patterns
Strategy: validation
Validate before calling
serializer = app.session_interface.get_signing_serializer # example context
from flask.json.tag import TaggedJSONSerializer
s = TaggedJSONSerializer()
if not any(t.key == '_myobj' for t in s.tags.values() if t.key):
s.register(MyTag) Type guard
def tag_key_free(serializer, key):
return key not in serializer.tags Try / catch
try:
serializer.register(MyTag)
except KeyError:
pass # already registered — only safe if it is the SAME tag class; otherwise pick a new key Prevention
- Choose unique tag keys that don't collide with Flask's built-in tags (' t', ' u', ' b', ' m', ' d', etc.)
- Register custom tags exactly once at app startup, not per-request or in reloadable code paths
- Use force=True on register() only when you intentionally replace an existing tag
- Guard registration behind an idempotent init function to survive module re-imports
When it happens
Trigger: Calling `app.session_interface.serializer.register(MyTag)` (or `TaggedJSONSerializer().register(...)`) where `MyTag.key` collides with a built-in tag key or with a tag you already registered — including registering the same custom tag class twice (e.g. once per worker init or in a module imported twice).
Common situations: Custom session serialization extensions registering tags at import time in a module that gets re-imported or executed in both the app factory and a blueprint; choosing a short key that collides with Flask's built-ins; app factories that call register() on a shared serializer instance for every created app.
Related errors
- Object of type {type(o).__name__} is not JSON serializable
- The session is unavailable because no secret key was set. S
- The view function did not return a valid response. The retur
- Working outside of application context. Attempted to use fu
- Working outside of request context. Attempted to use functi
AI-assisted analysis of pallets/flask@6a2f545bfd (2026-07-31).
Data as JSON: /data/errors/e6e5f55392cffdaf.json.
Report an issue: GitHub ↗.