{"record":{"id":"4c7b2de34773ae76","repo":"makeplane/plane","slug":"invalid-filterset","errorCode":"invalid_filterset","errorMessage":"Invalid filter parameters","messagePattern":"Invalid filter parameters","errorType":"validation","errorClass":"DRFValidationError","httpStatus":400,"severity":"error","filePath":"apps/api/plane/utils/filters/filter_backend.py","lineNumber":279,"sourceCode":"        qd = QueryDict(mutable=True)\n        for key, value in processed_conditions.items():\n            # Default serialization to string; QueryDict expects strings\n            if isinstance(value, list):\n                # Repeat key for list values (e.g., __in)\n                qd.setlist(key, [str(v) for v in value])\n            else:\n                qd[key] = \"\" if value is None else str(value)\n\n        qd = qd.copy()\n        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","sourceCodeStart":261,"sourceCodeEnd":297,"githubUrl":"https://github.com/makeplane/plane/blob/1c8a60f858d8472aa56e29994ec1c7926da2c6ce/apps/api/plane/utils/filters/filter_backend.py#L261-L297","documentation":"Raised by _build_leaf_q when filterset_class(data=..., queryset=...).is_valid() returns False. The underlying django_filters FilterSet runs its own per-field validation (range ordering, choice constraints, type coercion), and the errors dict is forwarded through translate_validation and embedded in the exception under 'errors'.","triggerScenarios":"GET .../?filters={\"sequence_id__range\":[10,5]} (range where start>end); GET .../?filters={\"state\":\"deleted\"} when state is a ChoiceFilter that does not include 'deleted'; non-numeric string sent to a NumberFilter.","commonSituations":"Semantic mismatch between client enum and server ChoiceFilter; reversed __range bounds; sending an ID that does not exist for a ModelChoiceFilter; type drift after a field changed from CharFilter to NumberFilter.","solutions":["Inspect the 'errors' field of the response — it carries per-field detail from the filterset.","Sort __range bounds so the smaller value comes first: [5, 10] not [10, 5].","Confirm the value is a member of the ChoiceFilter choices or a valid PK for ModelChoiceFilter.","If the value should be permitted, widen the filterset's choices or field definition."],"exampleFix":"// before\n?filters={\"sequence_id__range\":[10,5]}\n// after\n?filters={\"sequence_id__range\":[5,10]}","handlingStrategy":"try-catch","validationCode":"fs = view.filterset_class(data=qd, queryset=qs)\nif not fs.is_valid():\n    # fs.errors is a dict of per-field error lists\n    raise ValueError(f'filterset invalid: {fs.errors}')","typeGuard":null,"tryCatchPattern":"try:\n    return backend.filter_queryset(request, qs, view)\nexcept DRFValidationError as e:\n    detail = e.detail\n    if isinstance(detail, dict) and detail.get('code') == 'invalid_filterset':\n        return Response({'field_errors': detail.get('errors')}, status=400)\n    raise","preventionTips":["Sort __range bounds ascending on the client.","Mirror the server's ChoiceFilter choices on the frontend pickers.","Send IDs only where ModelChoiceFilter is used."],"tags":["filters","validation","django-filters","api"],"backgroundTag":null,"analyzedSha":"1c8a60f858d8472aa56e29994ec1c7926da2c6ce","analyzedAt":"2026-08-12T14:44:31.636Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}