{"record":{"id":"f05dd3d58c1be3e8","repo":"HumanSignal/label-studio","slug":"cannot-update-read-only-field-field","errorCode":null,"errorMessage":"Cannot update read-only field: {field}","messagePattern":"Cannot update read-only field: (.+?)","errorType":"http","errorClass":"MethodNotAllowed","httpStatus":405,"severity":"error","filePath":"label_studio/users/api.py","lineNumber":191,"sourceCode":"\n    def create(self, request, *args, **kwargs):\n        return super(UserAPI, self).create(request, *args, **kwargs)\n\n    def perform_create(self, serializer):\n        instance = serializer.save()\n        self.request.user.active_organization.add_user(instance)\n\n    def retrieve(self, request, *args, **kwargs):\n        return super(UserAPI, self).retrieve(request, *args, **kwargs)\n\n    def partial_update(self, request, *args, **kwargs):\n        result = super(UserAPI, self).partial_update(request, *args, **kwargs)\n\n        # throw MethodNotAllowed if read-only fields are attempted to be updated\n        read_only_fields = self.get_serializer_class().Meta.read_only_fields\n        for field in read_only_fields:\n            if field in request.data:\n                raise MethodNotAllowed('PATCH', detail=f'Cannot update read-only field: {field}')\n\n        # newsletters\n        if 'allow_newsletters' in request.data:\n            user = User.objects.get(id=request.user.id)  # we need an updated user\n            request.user.advanced_json = {  # request.user instance will be unchanged in request all the time\n                'email': user.email,\n                'allow_newsletters': user.allow_newsletters,\n                'update-notifications': 1,\n                'new-user': 0,\n            }\n        return result\n\n    def destroy(self, request, *args, **kwargs):\n        return super(UserAPI, self).destroy(request, *args, **kwargs)\n\n\n@method_decorator(\n    name='post',","sourceCodeStart":173,"sourceCodeEnd":209,"githubUrl":"https://github.com/HumanSignal/label-studio/blob/0b49e9b53917880baf1dd85d574fe5541a9aafb2/label_studio/users/api.py#L173-L209","documentation":"UserAPI.partial_update in label_studio/users/api.py raises DRF MethodNotAllowed('PATCH') when the PATCH body includes any field listed in UserSerializerUpdate.Meta.read_only_fields. The super().partial_update() call has already run by this point, so the write succeeded but the request is then rejected with 405.","triggerScenarios":"PATCH /api/current-user (or /api/users/<id>/) with a body containing read-only fields such as 'id', 'username', or other Meta.read_only_fields entries — e.g. {'id': 5, 'first_name': 'A'} or echoing back the full user object from a prior GET.","commonSituations":"Clients doing GET then PATCH with the full response body echoed back (including id/username); UI forms that bind all user fields and submit everything; SDK wrappers that merge the object with updates before sending.","solutions":["Remove read-only fields (e.g. 'id', 'username') from the PATCH body and send only mutable fields","Build the payload explicitly instead of echoing the GET response","Strip read-only fields client-side: payload = {k: v for k, v in user.items() if k not in read_only_fields}","Check UserSerializerUpdate.Meta.read_only_fields for the exact blocked field names"],"exampleFix":"// before\nclient.patch(f\"/api/users/{uid}\", {\"id\": uid, \"first_name\": \"Ann\"})\n// after\nclient.patch(f\"/api/users/{uid}\", {\"first_name\": \"Ann\"})","handlingStrategy":"validation","validationCode":"READ_ONLY = {'id', 'username'}  # UserSerializerUpdate.Meta.read_only_fields\npayload = {k: v for k, v in request_body.items() if k not in READ_ONLY}","typeGuard":null,"tryCatchPattern":"try:\n    client.update_user(payload)\nexcept MethodNotAllowed as e:\n    detail = getattr(e, 'detail', str(e))\n    m = re.search(r'read-only field: (\\w+)', str(detail))\n    if m:\n        payload.pop(m.group(1), None)\n        client.update_user(payload)\n    else:\n        raise","preventionTips":["Send only the fields you intend to change, never the full GET response echoed back","Diff your PATCH body against UserSerializerUpdate.Meta.read_only_fields","Build update payloads explicitly instead of spreading whole objects","Strip id/username from form data before submitting user updates"],"tags":["rest-api","http-405","users-api","read-only-field"],"backgroundTag":"read-only-field-update","analyzedSha":"0b49e9b53917880baf1dd85d574fe5541a9aafb2","analyzedAt":"2026-08-29T00:39:52.578Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}