apache/superset · error · DatasourceNotFoundValidationError
Datasource does not exist
Error message
Datasource does not exist
What it means
DatasourceNotFoundValidationError raised in UpdateRLSRuleCommand.validate when the payload includes 'tables' but fewer SqlaTable rows match self._tables than requested — at least one dataset id in the update does not exist. Access (raise_for_datasource_access) is checked only after all ids resolve.
Source
Thrown at superset/commands/security/update.py:79
) from ex
return updated_model
def validate(self) -> None:
self._model = RLSDAO.find_by_id(int(self._model_id))
if not self._model:
raise RLSRuleNotFoundError()
# Datasource access is validated before revealing whether the
# requested name is already in use, so an unauthorized caller can't
# use the duplicate-name response to enumerate rule names.
if "tables" in self._properties:
tables = (
db.session.query(SqlaTable)
.filter(SqlaTable.id.in_(self._tables)) # type: ignore[attr-defined]
.all()
)
if len(tables) != len(self._tables):
raise DatasourceNotFoundValidationError()
raise_for_datasource_access(tables)
self._properties["tables"] = tables
else:
# A partial update that omits ``tables`` still mutates the rule, so
# enforce datasource access against the rule's existing tables to
# avoid letting a caller edit a rule bound to datasources they
# cannot access.
raise_for_datasource_access(self._model.tables)
name = self._properties.get("name")
if name and not RLSDAO.validate_uniqueness(name, self._model.id):
raise ValidationError(
{"name": [_("A rule with this name already exists.")]}
)
# Only resolve and overwrite the relationships that are actually present
# in the request body. A partial update (e.g. changing only the name)
# must leave the rule's existing tables/subjects bindings untouchedView on GitHub (pinned to f4587218dd)
Solutions
- Resolve dataset ids at request time via GET /api/v1/dataset/ (filter by table_name/uuid) instead of hard-coding
- Drop the stale id from the 'tables' array and retry
- Recreate the missing dataset if it should still exist
Example fix
# before
client.put(rls_url, json={'tables': [7, 999]}) # 999 gone
# after
ds_id = client.get('/api/v1/dataset/?q=(table_name:eq:my_table)').json()['result'][0]['id']
client.put(rls_url, json={'tables': [7, ds_id]}) Defensive patterns
Strategy: validation
Validate before calling
known = {d['id'] for d in client.get('/api/v1/dataset/').json()['result']}
assert set(props['tables']) <= known Try / catch
from superset.commands.exceptions import DatasourceNotFoundValidationError
try:
UpdateRLSRuleCommand(rid, props).run()
except DatasourceNotFoundValidationError:
props['tables'] = resolve_dataset_ids_by_name(props['tables'])
UpdateRLSRuleCommand(rid, props).run() Prevention
- Look up dataset ids by name/uuid right before the PUT
- Remove deleted datasets from rule-binding payloads
- Watch for id churn after metadata migrations
When it happens
Trigger: PUT /api/v1/rowlevelsecurity/{id} with 'tables' containing a deleted/invalid dataset id; rebinding a rule to datasets whose ids changed after a metadata migration.
Common situations: Updating rule bindings with ids copied from another environment; datasets dropped by a cleanup job while the rule edit was in flight.
Related errors
- Datasource does not exist
- Annotation not found.
- Annotation layer not found.
- Annotation layer not found.
- Chart not found.
AI-assisted analysis of apache/superset@f4587218dd (2026-08-14).
Data as JSON: /api/errors/68a2dc30d5d35552.
Report an issue: GitHub.