apache/superset · error · DatasourceNotFoundValidationError

Datasource does not exist

Error message

Datasource does not exist

What it means

DatasourceNotFoundValidationError is raised in CreateRLSRuleCommand.validate when the number of SqlaTable rows matching self._tables does not equal len(self._tables): at least one requested table/dataset id does not exist. Datasource checks run before name-uniqueness so callers cannot probe rule names of datasources they cannot access.

Source

Thrown at superset/commands/security/create.py:70

            # The preflight uniqueness check in ``validate`` isn't atomic with
            # this insert, so fall back to the database's unique constraint
            # and translate it into the same descriptive validation error.
            raise ValidationError(
                {"name": [_("A rule with this name already exists.")]}
            ) from ex
        return new_model

    def validate(self) -> None:
        # Datasource existence/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.
        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

        name = self._properties.get("name")
        if name and not RLSDAO.validate_uniqueness(name):
            raise ValidationError(
                {"name": [_("A rule with this name already exists.")]}
            )

        if (
            self._properties.get("filter_type")
            == RowLevelSecurityFilterType.REGULAR.value
            and not self._subjects
        ):
            raise ValidationError(
                {"subjects": ["Regular RLS filters require at least one subject."]}
            )

View on GitHub (pinned to f4587218dd)

Solutions

  1. Resolve datasets by name/uuid (GET /api/v1/dataset/) at runtime instead of hard-coding integer ids
  2. Remove or correct the stale id in the payload and retry the POST
  3. If the dataset was deleted, recreate it first, then create the RLS rule

Example fix

# before
payload['tables'] = [42]  # deleted dataset id

# after
ds = client.get('/api/v1/dataset/?q=(table_name:eq:my_table)').json()['result'][0]
payload['tables'] = [ds['id']]
Defensive patterns

Strategy: validation

Validate before calling

known = {d['id'] for d in client.get('/api/v1/dataset/').json()['result']}
assert set(table_ids) <= known, f'unknown dataset ids: {set(table_ids) - known}'

Try / catch

from superset.commands.exceptions import DatasourceNotFoundValidationError
try:
    CreateRLSRuleCommand(props).run()
except DatasourceNotFoundValidationError:
    table_ids = resolve_dataset_ids_by_name(props['tables'])
    CreateRLSRuleCommand({**props, 'tables': table_ids}).run()

Prevention

When it happens

Trigger: POST /api/v1/rowlevelsecurity with a 'tables' array containing a dataset id that was deleted, belongs to another environment, or is simply mistyped.

Common situations: Hard-coded dataset ids in provisioning scripts after a metadata DB reset; datasets refreshed/recreated with new ids; copying an RLS rule definition between staging and production where ids differ.

Related errors


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