HumanSignal/label-studio · error · MethodNotAllowed
Cannot update read-only field: {field}
Error message
Cannot update read-only field: {field} What it means
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.
Source
Thrown at label_studio/users/api.py:191
def create(self, request, *args, **kwargs):
return super(UserAPI, self).create(request, *args, **kwargs)
def perform_create(self, serializer):
instance = serializer.save()
self.request.user.active_organization.add_user(instance)
def retrieve(self, request, *args, **kwargs):
return super(UserAPI, self).retrieve(request, *args, **kwargs)
def partial_update(self, request, *args, **kwargs):
result = super(UserAPI, self).partial_update(request, *args, **kwargs)
# throw MethodNotAllowed if read-only fields are attempted to be updated
read_only_fields = self.get_serializer_class().Meta.read_only_fields
for field in read_only_fields:
if field in request.data:
raise MethodNotAllowed('PATCH', detail=f'Cannot update read-only field: {field}')
# newsletters
if 'allow_newsletters' in request.data:
user = User.objects.get(id=request.user.id) # we need an updated user
request.user.advanced_json = { # request.user instance will be unchanged in request all the time
'email': user.email,
'allow_newsletters': user.allow_newsletters,
'update-notifications': 1,
'new-user': 0,
}
return result
def destroy(self, request, *args, **kwargs):
return super(UserAPI, self).destroy(request, *args, **kwargs)
@method_decorator(
name='post',View on GitHub (pinned to 0b49e9b539)
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
Example fix
// before
client.patch(f"/api/users/{uid}", {"id": uid, "first_name": "Ann"})
// after
client.patch(f"/api/users/{uid}", {"first_name": "Ann"}) Defensive patterns
Strategy: validation
Validate before calling
READ_ONLY = {'id', 'username'} # UserSerializerUpdate.Meta.read_only_fields
payload = {k: v for k, v in request_body.items() if k not in READ_ONLY} Try / catch
try:
client.update_user(payload)
except MethodNotAllowed as e:
detail = getattr(e, 'detail', str(e))
m = re.search(r'read-only field: (\w+)', str(detail))
if m:
payload.pop(m.group(1), None)
client.update_user(payload)
else:
raise Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Annotation must have "result" fields
- Prediction must have "result" fields
- All tasks are empty (None)
- data is not a list
- data is empty
AI-assisted analysis of HumanSignal/label-studio@0b49e9b539 (2026-08-29).
Data as JSON: /api/errors/f05dd3d58c1be3e8.
Report an issue: GitHub.