apache/superset · error · TagNotFoundValidationError

Tag ID {tag_id} not found

Error message

Tag ID {tag_id} not found

What it means

Inside validate_tags, after the permission check passes, each newly added tag ID is checked with TagDAO.find_by_id; an unknown ID raises TagNotFoundValidationError with the offending ID. This guards against associating nonexistent custom tags with dashboards/charts/datasets.

Source

Thrown at superset/commands/utils.py:248

    if Counter(current_custom_tags) == Counter(new_tag_ids):
        return

    # No perm to tags assets
    if not (
        security_manager.can_access("can_write", "Tag")
        or security_manager.can_access("can_tag", object_type.name.capitalize())
    ):
        validation_error = (
            f"You do not have permission to manage tags on {object_type.name}s"
        )
        raise TagForbiddenError(validation_error)

    # Validate if new tags already exist
    additional_tags = [tag for tag in new_tag_ids if tag not in current_custom_tags]
    for tag_id in additional_tags:
        if not TagDAO.find_by_id(tag_id):
            validation_error = f"Tag ID {tag_id} not found"
            raise TagNotFoundValidationError(validation_error)

    return


def update_tags(
    object_type: ObjectType,
    object_id: int,
    current_tags: list[Tag],
    new_tag_ids: list[int],
) -> None:
    """
    Helper function for update commands, to update the tag relationship.

    :param object_id: The object (dashboard, chart, etc) ID
    :param object_type: The object type
    :param current_tags: list of current tags
    :param new_tag_ids: list of tags specified in the update payload
    """

View on GitHub (pinned to f4587218dd)

Solutions

  1. Fetch the current tag list (GET /api/v1/tag) and map names to live IDs before submitting.
  2. Create missing tags first (if the user has can_write on Tag), then reference their IDs.
  3. Remove nonexistent tag IDs from the payload.

Example fix

# before
{"tags": [5, 999]}  # 999 does not exist

# after
valid = {t.id for t in TagDAO.find_all()}  # or GET /api/v1/tag
{"tags": [t for t in [5, 999] if t in valid]}
Defensive patterns

Strategy: validation

Validate before calling

from superset.daos.tag import TagDAO
bad = [tid for tid in new_tag_ids if TagDAO.find_by_id(tid) is None]
if bad:
    raise ValueError(f"unknown tag ids: {bad}")

Try / catch

try:
    update_tags(object_type, object_id, current_tags, new_tag_ids)
except TagNotFoundValidationError as e:
    drop_ids_from_message_and_retry(e)

Prevention

When it happens

Trigger: PATCHing an object with a tags array containing an ID that is not an existing custom tag — stale tag list from another environment, deleted tag, or hand-crafted ID.

Common situations: Importing dashboards with tag references without importing tags; tag deleted by an admin while a user had the tag picker open; scripts copying tag IDs across instances.

Related errors


AI-assisted analysis of apache/superset@f4587218dd (2026-08-14). Data as JSON: /api/errors/0764b732bafd162e. Report an issue: GitHub.