{"record":{"id":"3b173b85c61d996d","repo":"makeplane/plane","slug":"missing-build-combined-q","errorCode":"missing_build_combined_q","errorMessage":"FilterSet must have build_combined_q method for complex filtering","messagePattern":"FilterSet must have build_combined_q method for complex filtering","errorType":"validation","errorClass":"DRFValidationError","httpStatus":400,"severity":"error","filePath":"apps/api/plane/utils/filters/filter_backend.py","lineNumber":289,"sourceCode":"        qd._mutable = False\n\n        # Instantiate the filterset with the actual queryset\n        # Custom filter methods may need access to the queryset for filtering\n        fs = filterset_class(data=qd, queryset=queryset)\n\n        if not fs.is_valid():\n            ve = translate_validation(fs.errors)\n            raise DRFValidationError(\n                {\n                    \"message\": \"Invalid filter parameters\",\n                    \"code\": \"invalid_filterset\",\n                    \"errors\": ve.detail,\n                }\n            )\n\n        # Build and return the combined Q object\n        if not hasattr(fs, \"build_combined_q\"):\n            raise DRFValidationError(\n                {\n                    \"message\": (\"FilterSet must have build_combined_q method for complex filtering\"),\n                    \"code\": \"missing_build_combined_q\",\n                }\n            )\n\n        return fs.build_combined_q()\n\n    def _get_max_depth(self, view):\n        \"\"\"Return the maximum allowed nesting depth for complex filters.\n\n        Falls back to class default if the view does not specify it or has\n        an invalid value.\n        \"\"\"\n        value = getattr(view, \"complex_filter_max_depth\", self.default_max_depth)\n        try:\n            value_int = int(value)\n            if value_int <= 0:","sourceCodeStart":271,"sourceCodeEnd":307,"githubUrl":"https://github.com/makeplane/plane/blob/1c8a60f858d8472aa56e29994ec1c7926da2c6ce/apps/api/plane/utils/filters/filter_backend.py#L271-L307","documentation":"Raised by _build_leaf_q when the resolved filterset_class instance lacks a build_combined_q method. The ComplexFilterBackend pipeline depends on a custom extension to django_filters (BaseFilterSet.build_combined_q) that returns a composed Q object instead of filtering the queryset directly; without it the backend cannot translate the leaf into a Q.","triggerScenarios":"A view points filterset_class at a vanilla django_filters.FilterSet subclass (or a hand-rolled one) instead of plane.utils.filters.BaseFilterSet; refactoring that swaps a custom filterset for a plain one.","commonSituations":"Replacing BaseFilterSet with a stock FilterSet during a cleanup; importing the wrong filterset class (same name from a different module); upgrading django_filters and dropping the mixin that supplied build_combined_q.","solutions":["Make the filterset inherit from plane.utils.filters.BaseFilterSet, which provides build_combined_q.","If you cannot inherit from BaseFilterSet, implement build_combined_q(self) on the filterset returning a django.db.models.Q.","Verify the import: `from plane.utils.filters import BaseFilterSet`."],"exampleFix":"# before\nimport django_filters\nclass IssueFilterSet(django_filters.FilterSet):\n    ...\n\n# after\nfrom plane.utils.filters import BaseFilterSet\nclass IssueFilterSet(BaseFilterSet):\n    ...","handlingStrategy":"validation","validationCode":"fs_cls = view.filterset_class\nassert hasattr(fs_cls, 'build_combined_q'), (\n    f'{fs_cls.__name__} must inherit from plane.utils.filters.BaseFilterSet '\n    'or implement build_combined_q'\n)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always inherit custom filtersets from plane.utils.filters.BaseFilterSet.","Add a unit test asserting build_combined_q is present on every filterset paired with ComplexFilterBackend."],"tags":["filters","config","django-filters","api"],"backgroundTag":null,"analyzedSha":"1c8a60f858d8472aa56e29994ec1c7926da2c6ce","analyzedAt":"2026-08-12T14:44:31.636Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}