apache/superset · warning · NoResultFound
Tagged object with object_id: {object_id}
Error message
Tagged object with object_id: {object_id} object_type: {object_type} and tag name: "{tag_name}" could not be found What it means
Raised by TagDAO.delete_tagged_object for a missing TaggedObject join row. The code's intent is to complain when no association between (tag, object_type, object_id) exists, but the guard is defective: `db.session.query(...).filter(...)` builds a Query object which is always truthy, so the branch is unreachable and the subsequent tagged_object.one() raises sqlalchemy.exc.NoResultFound instead. The literal in the source also contains embedded line-continuation backslashes, so the rendered message has unexpected whitespace.
Source
Thrown at superset/daos/tag.py:89
@staticmethod
def delete_tagged_object(
object_type: ObjectType, object_id: int, tag_name: str
) -> None:
"""
deletes a tagged object by the object_id, object_type, and tag_name
"""
tag = TagDAO.find_by_name(tag_name.strip())
if not tag:
raise NoResultFound(message=f"Tag with name {tag_name} does not exist.")
tagged_object = db.session.query(TaggedObject).filter(
TaggedObject.tag_id == tag.id,
TaggedObject.object_type == object_type,
TaggedObject.object_id == object_id,
)
if not tagged_object:
raise NoResultFound(
message=f'Tagged object with object_id: {object_id} \
object_type: {object_type} \
and tag name: "{tag_name}" could not be found'
)
db.session.delete(tagged_object.one())
@staticmethod
def delete_tags(tag_names: list[str]) -> None:
"""
deletes tags from a list of tag names
"""
tags_to_delete = []
for name in tag_names:
tag_name = name.strip()
if not TagDAO.find_by_name(tag_name):
raise NoResultFound(message=f"Tag with name {tag_name} does not exist.")
tags_to_delete.append(tag_name)View on GitHub (pinned to f4587218dd)
Solutions
- Check existence with .one_or_none() on the association before deleting, mirroring the fix the DAO itself needs.
- Make the operation idempotent: treat 'association already absent' as success.
- Upstream-quality note: the DAO guard should use `tagged_object.one_or_none()` and raise on None; report or patch it, since the current code leaks sqlalchemy.exc.NoResultFound.
- Avoid racing parallel untag requests for the same object; serialize them or accept idempotent no-ops.
Example fix
# before
TagDAO.delete_tagged_object(object_type, object_id, tag_name) # missing association -> raw sqlalchemy NoResultFound (500)
# after
from superset.models.tags import TaggedObject, ObjectType
assoc = (
db.session.query(TaggedObject)
.filter(
TaggedObject.tag_id == tag.id,
TaggedObject.object_type == object_type,
TaggedObject.object_id == object_id,
)
.one_or_none()
)
if assoc:
db.session.delete(assoc)
# else: association already gone — no-op Defensive patterns
Strategy: validation
Validate before calling
from superset import db
from superset.models.tags import TaggedObject, ObjectType
def tagged_object_exists(tag_id: int, object_type: ObjectType, object_id: int) -> bool:
return db.session.query(TaggedObject.id).filter(
TaggedObject.tag_id == tag_id,
TaggedObject.object_type == object_type,
TaggedObject.object_id == object_id,
).first() is not None Try / catch
from sqlalchemy.exc import NoResultFound # current DAO leaks the raw SA error
try:
TagDAO.delete_tagged_object(object_type, object_id, tag_name)
except NoResultFound:
pass # association already absent — idempotent success Prevention
- Guard with one_or_none() existence checks instead of relying on the DAO's broken truthiness guard.
- Make untag operations idempotent; treat already-removed associations as success.
- Watch upstream for a fix to the DAO guard (it tests a Query object, which is always truthy).
When it happens
Trigger: Deleting a tag-object association that was already removed; passing an object_id/object_type pair that was never tagged with this tag; concurrent deletes of the same association.
Common situations: Double-submit of an untag action in the UI; scripts that untag objects by id after the tag was reassigned; any code path that reaches the broken guard — it silently converts to an unwrapped SQLAlchemy NoResultFound (HTTP 500) rather than the intended typed error.
Related errors
- Tag with name {tag_name} does not exist.
- Tag not found.
- CSS template not found.
- Tag ID {tag_id} not found
- Chart not found.
AI-assisted analysis of apache/superset@f4587218dd (2026-08-14).
Data as JSON: /api/errors/65e84818f474ff79.
Report an issue: GitHub.