{"id":"e6e5f55392cffdaf","repo":"pallets/flask","slug":"tag-key-is-already-registered","errorCode":null,"errorMessage":"Tag '{key}' is already registered.","messagePattern":"Tag '(.+?)' is already registered\\.","errorType":"exception","errorClass":"KeyError","httpStatus":null,"severity":"error","filePath":"src/flask/json/tag.py","lineNumber":280,"sourceCode":"        \"\"\"Register a new tag with this serializer.\n\n        :param tag_class: tag class to register. Will be instantiated with this\n            serializer instance.\n        :param force: overwrite an existing tag. If false (default), a\n            :exc:`KeyError` is raised.\n        :param index: index to insert the new tag in the tag order. Useful when\n            the new tag is a special case of an existing tag. If ``None``\n            (default), the tag is appended to the end of the order.\n\n        :raise KeyError: if the tag key is already registered and ``force`` is\n            not true.\n        \"\"\"\n        tag = tag_class(self)\n        key = tag.key\n\n        if key:\n            if not force and key in self.tags:\n                raise KeyError(f\"Tag '{key}' is already registered.\")\n\n            self.tags[key] = tag\n\n        if index is None:\n            self.order.append(tag)\n        else:\n            self.order.insert(index, tag)\n\n    def tag(self, value: t.Any) -> t.Any:\n        \"\"\"Convert a value to a tagged representation if necessary.\"\"\"\n        for tag in self.order:\n            if tag.check(value):\n                return tag.tag(value)\n\n        return value\n\n    def untag(self, value: dict[str, t.Any]) -> t.Any:\n        \"\"\"Convert a tagged representation back to the original type.\"\"\"","sourceCodeStart":262,"sourceCodeEnd":298,"githubUrl":"https://github.com/pallets/flask/blob/6a2f545bfd8ed31e19066a299296917e034aca58/src/flask/json/tag.py#L262-L298","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"# before\nclass TagOrderedDict(JSONTag):\n    key = \" t\"  # collides with built-in TagTuple\nserializer.register(TagOrderedDict)\n\n# after\nclass TagOrderedDict(JSONTag):\n    key = \" od\"\nif \" od\" not in serializer.tags:\n    serializer.register(TagOrderedDict, index=0)","handlingStrategy":"validation","validationCode":"serializer = app.session_interface.get_signing_serializer  # example context\nfrom flask.json.tag import TaggedJSONSerializer\ns = TaggedJSONSerializer()\nif not any(t.key == '_myobj' for t in s.tags.values() if t.key):\n    s.register(MyTag)","typeGuard":"def tag_key_free(serializer, key):\n    return key not in serializer.tags","tryCatchPattern":"try:\n    serializer.register(MyTag)\nexcept KeyError:\n    pass  # already registered — only safe if it is the SAME tag class; otherwise pick a new key","preventionTips":["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"],"tags":["flask","json","session","serialization","python"],"analyzedSha":"6a2f545bfd8ed31e19066a299296917e034aca58","analyzedAt":"2026-07-31T19:13:49.921Z","schemaVersion":2}