{"record":{"id":"68a2dc30d5d35552","repo":"apache/superset","slug":"datasource-does-not-exist-68a2dc","errorCode":null,"errorMessage":"Datasource does not exist","messagePattern":"Datasource does not exist","errorType":"validation","errorClass":"DatasourceNotFoundValidationError","httpStatus":404,"severity":"error","filePath":"superset/commands/security/update.py","lineNumber":79,"sourceCode":"            ) from ex\n        return updated_model\n\n    def validate(self) -> None:\n        self._model = RLSDAO.find_by_id(int(self._model_id))\n        if not self._model:\n            raise RLSRuleNotFoundError()\n\n        # Datasource access is validated before revealing whether the\n        # requested name is already in use, so an unauthorized caller can't\n        # use the duplicate-name response to enumerate rule names.\n        if \"tables\" in self._properties:\n            tables = (\n                db.session.query(SqlaTable)\n                .filter(SqlaTable.id.in_(self._tables))  # type: ignore[attr-defined]\n                .all()\n            )\n            if len(tables) != len(self._tables):\n                raise DatasourceNotFoundValidationError()\n            raise_for_datasource_access(tables)\n            self._properties[\"tables\"] = tables\n        else:\n            # A partial update that omits ``tables`` still mutates the rule, so\n            # enforce datasource access against the rule's existing tables to\n            # avoid letting a caller edit a rule bound to datasources they\n            # cannot access.\n            raise_for_datasource_access(self._model.tables)\n\n        name = self._properties.get(\"name\")\n        if name and not RLSDAO.validate_uniqueness(name, self._model.id):\n            raise ValidationError(\n                {\"name\": [_(\"A rule with this name already exists.\")]}\n            )\n\n        # Only resolve and overwrite the relationships that are actually present\n        # in the request body. A partial update (e.g. changing only the name)\n        # must leave the rule's existing tables/subjects bindings untouched","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/apache/superset/blob/f4587218dd19d046c3e4d00063e7d27f8a2ed354/superset/commands/security/update.py#L61-L97","documentation":"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.","triggerScenarios":"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.","commonSituations":"Updating rule bindings with ids copied from another environment; datasets dropped by a cleanup job while the rule edit was in flight.","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"],"exampleFix":"# before\nclient.put(rls_url, json={'tables': [7, 999]})  # 999 gone\n\n# after\nds_id = client.get('/api/v1/dataset/?q=(table_name:eq:my_table)').json()['result'][0]['id']\nclient.put(rls_url, json={'tables': [7, ds_id]})","handlingStrategy":"validation","validationCode":"known = {d['id'] for d in client.get('/api/v1/dataset/').json()['result']}\nassert set(props['tables']) <= known","typeGuard":null,"tryCatchPattern":"from superset.commands.exceptions import DatasourceNotFoundValidationError\ntry:\n    UpdateRLSRuleCommand(rid, props).run()\nexcept DatasourceNotFoundValidationError:\n    props['tables'] = resolve_dataset_ids_by_name(props['tables'])\n    UpdateRLSRuleCommand(rid, props).run()","preventionTips":["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"],"tags":["rls","datasource","not-found","update"],"backgroundTag":null,"analyzedSha":"f4587218dd19d046c3e4d00063e7d27f8a2ed354","analyzedAt":"2026-08-14T22:39:27.425Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}