{"record":{"id":"5156cc0768acf8f9","repo":"apache/superset","slug":"regular-rls-filters-require-at-least-one-subject-5156cc","errorCode":null,"errorMessage":"Regular RLS filters require at least one subject.","messagePattern":"Regular RLS filters require at least one subject\\.","errorType":"validation","errorClass":"ValidationError","httpStatus":422,"severity":"error","filePath":"superset/commands/security/update.py","lineNumber":114,"sourceCode":"        # in the request body. A partial update (e.g. changing only the name)\n        # must leave the rule's existing tables/subjects bindings untouched\n        # rather than replacing them with empty lists.\n        if \"subjects\" in self._properties:\n            subjects = populate_subject_list(\n                self._subjects,\n                default_to_user=False,\n            )\n            self._properties[\"subjects\"] = subjects\n        else:\n            subjects = list(self._model.subjects)\n\n        filter_type = self._properties.get(\"filter_type\", self._model.filter_type)\n        filter_type_value = getattr(filter_type, \"value\", filter_type)\n        if (\n            filter_type_value == RowLevelSecurityFilterType.REGULAR.value\n            and not subjects\n        ):\n            raise ValidationError(\n                {\"subjects\": [\"Regular RLS filters require at least one subject.\"]}\n            )\n","sourceCodeStart":96,"sourceCodeEnd":117,"githubUrl":"https://github.com/apache/superset/blob/f4587218dd19d046c3e4d00063e7d27f8a2ed354/superset/commands/security/update.py#L96-L117","documentation":"ValidationError raised in UpdateRLSRuleCommand.validate when the effective filter_type (payload value or the rule's stored value) resolves to REGULAR while the effective subjects list (payload 'subjects' or the rule's existing bindings) is empty — a regular RLS filter must keep at least one subject.","triggerScenarios":"PUT switching filter_type to 'Regular' on a rule with no subjects; PUT with 'subjects': [] on a Regular rule; a partial update that only changes filter_type while the stored rule has no subject bindings (subjects then default to the empty stored list).","commonSituations":"Promoting a Base filter to Regular without adding subjects; clearing subjects to 'reset' a rule; partial payloads whose defaults surprise the author.","solutions":["Include a non-empty 'subjects' array in the same PUT (e.g. a role subject) whenever filter_type is Regular","Alternatively switch filter_type to 'Base' if the clause must be subject-independent","Read the rule first (GET) to know the stored subjects/type your partial update will combine with"],"exampleFix":"# before\nclient.put(url, json={'filter_type': 'Regular'})  # rule has no subjects\n\n# after\nclient.put(url, json={'filter_type': 'Regular',\n                       'subjects': [{'subject_type': 'Role', 'subject': 'Gamma'}]})","handlingStrategy":"validation","validationCode":"eff_type = props.get('filter_type', stored_rule['filter_type'])\neff_subjects = props['subjects'] if 'subjects' in props else stored_rule['subjects']\nif eff_type == 'Regular':\n    assert eff_subjects, 'Regular rules need >=1 subject'","typeGuard":"def update_keeps_regular_subjects(props: dict, stored: dict) -> bool:\n    ftype = props.get('filter_type', stored.get('filter_type'))\n    ftype = getattr(ftype, 'value', ftype)\n    subjects = props['subjects'] if 'subjects' in props else stored.get('subjects', [])\n    return ftype != 'Regular' or bool(subjects)","tryCatchPattern":"from superset.commands.exceptions import ValidationError\ntry:\n    UpdateRLSRuleCommand(rid, props).run()\nexcept ValidationError as e:\n    if 'subjects' in e.normalized_messages():\n        props['subjects'] = [{'subject_type': 'Role', 'subject': 'Gamma'}]\n        UpdateRLSRuleCommand(rid, props).run()","preventionTips":["GET the rule first so partial updates merge against known stored values","Never send 'subjects': [] on a Regular rule","Pair any filter_type change with an explicit subjects payload"],"tags":["rls","validation","subjects","filter-type"],"backgroundTag":null,"analyzedSha":"f4587218dd19d046c3e4d00063e7d27f8a2ed354","analyzedAt":"2026-08-14T22:39:27.425Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}