{"record":{"id":"0764b732bafd162e","repo":"apache/superset","slug":"tag-id-tag-id-not-found","errorCode":null,"errorMessage":"Tag ID {tag_id} not found","messagePattern":"Tag ID (.+?) not found","errorType":"validation","errorClass":"TagNotFoundValidationError","httpStatus":null,"severity":"error","filePath":"superset/commands/utils.py","lineNumber":248,"sourceCode":"    if Counter(current_custom_tags) == Counter(new_tag_ids):\n        return\n\n    # No perm to tags assets\n    if not (\n        security_manager.can_access(\"can_write\", \"Tag\")\n        or security_manager.can_access(\"can_tag\", object_type.name.capitalize())\n    ):\n        validation_error = (\n            f\"You do not have permission to manage tags on {object_type.name}s\"\n        )\n        raise TagForbiddenError(validation_error)\n\n    # Validate if new tags already exist\n    additional_tags = [tag for tag in new_tag_ids if tag not in current_custom_tags]\n    for tag_id in additional_tags:\n        if not TagDAO.find_by_id(tag_id):\n            validation_error = f\"Tag ID {tag_id} not found\"\n            raise TagNotFoundValidationError(validation_error)\n\n    return\n\n\ndef update_tags(\n    object_type: ObjectType,\n    object_id: int,\n    current_tags: list[Tag],\n    new_tag_ids: list[int],\n) -> None:\n    \"\"\"\n    Helper function for update commands, to update the tag relationship.\n\n    :param object_id: The object (dashboard, chart, etc) ID\n    :param object_type: The object type\n    :param current_tags: list of current tags\n    :param new_tag_ids: list of tags specified in the update payload\n    \"\"\"","sourceCodeStart":230,"sourceCodeEnd":266,"githubUrl":"https://github.com/apache/superset/blob/f4587218dd19d046c3e4d00063e7d27f8a2ed354/superset/commands/utils.py#L230-L266","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Fetch the current tag list (GET /api/v1/tag) and map names to live IDs before submitting.","Create missing tags first (if the user has can_write on Tag), then reference their IDs.","Remove nonexistent tag IDs from the payload."],"exampleFix":"# before\n{\"tags\": [5, 999]}  # 999 does not exist\n\n# after\nvalid = {t.id for t in TagDAO.find_all()}  # or GET /api/v1/tag\n{\"tags\": [t for t in [5, 999] if t in valid]}","handlingStrategy":"validation","validationCode":"from superset.daos.tag import TagDAO\nbad = [tid for tid in new_tag_ids if TagDAO.find_by_id(tid) is None]\nif bad:\n    raise ValueError(f\"unknown tag ids: {bad}\")","typeGuard":null,"tryCatchPattern":"try:\n    update_tags(object_type, object_id, current_tags, new_tag_ids)\nexcept TagNotFoundValidationError as e:\n    drop_ids_from_message_and_retry(e)","preventionTips":["Map tag names to fresh IDs at request time","Create tags before referencing them"],"tags":["tags","not-found","validation","backend"],"backgroundTag":null,"analyzedSha":"f4587218dd19d046c3e4d00063e7d27f8a2ed354","analyzedAt":"2026-08-14T22:39:27.425Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}