scim replace operation failed read-only attribute
For engineers debugging SCIM PATCH failures on immutable fields. Use when a replace operation returns 400 because the attribute is read-only in the provider schema. Key triggers: patching id or meta, userName locked after creation, custom read-only fields. Not for 401 auth failures or 404 missing-user errors.
Fix SCIM PATCH failing on a read-only attribute
TL;DR
The provider rejected the replace operation because the attribute is read-only in its schema - id, meta attributes, userName in some providers, or custom fields the provider locks down. Drop that attribute and PATCH only writable attributes. Check the provider's /Schemas endpoint to see exactly which attributes carry readOnly=true not guessing.
The error
PATCH the SCIM v2 user resource (DELETE) -> 400 Bad Request
{"schemas":["urn:ietf:params:scim:api:messages:2.0:Error"],"detail":"Attribute is read-only and cannot be modified","status":"400"}Use this skill
Agent? Search Vectle for this error:
curl -s "https://vectle.com/api/v1/search?q=scim%20replace%20operation%20failed%20read-only%20attribute"Fix it
Step 1: Read the provider's schema to find the read-only attributes
curl -s "https://yourapp.example.com/scim/v2/Schemas/urn:ietf:params:scim:schemas:core:2.0:User" -H "your auth header bearer value]" | python3 -c "import json,sys; s=json.load(sys.stdin); print([a['name'] for a in s['attributes'] if a.get('readOnly')])"Expected: a list naming the read-only attributes. The attribute in the failed PATCH should be on it.
Step 2: Strip read-only attributes from the PATCH
Rewrite the PATCH operations to touch only mutable attributes. Drop id, meta sub-attributes, and anything flagged readOnly from the payload.Expected: the payload contains only writable paths.
Step 3: Re-send the PATCH
curl -s -X PATCH "https://yourapp.example.comthe SCIM v2 user resource (DELETE)" -H "your auth header bearer value]" -H "Content-Type: application/scim+json" -d '{"schemas":["urn:ietf:params:scim:api:messages:2.0:PatchOp"],"Operations":[{"op":"replace","path":"name.givenName","value":"[first name]"}]}'Expected: HTTP 200 and the writable attribute updates.
Step 4: Fix the IdP attribute mapping so it stops sending the read-only field
In the IdP provisioning attribute mappings, unmap or exclude the read-only target attribute so future syncs never include it in PATCH operations.Expected: the preview no longer emits the read-only attribute.
Step 5: Re-run the failed provisioning task
Retry the failed task in the IdP provisioning queue and confirm it completes.Expected: success with no 400. The mapping fix prevents recurrence.
When this applies
- SCIM PATCH/replace returns 400 naming a read-only attribute
- Provisioning updates fail while creates succeed
- The payload includes id, meta, or provider-locked fields
When it doesn't
- The failure is 401 or 403 (credentials)
- The attribute should be writable but is rejected anyway (provider bug or wrong path syntax)
- Creates fail with 400 (schema violation on create, different issue)
Compatibility
SCIM 2.0 per RFC 7644 PATCH semantics. Applies to any SCIM provider enforcing attribute mutability.
Variant phrasings
scim patch 400 read only attribute
Same fix. The schema endpoint is authoritative; provider docs can lag behind the actual enforcement.
okta scim replace failed mutability
In Okta, the fix lives in the app's Profile Editor mappings - exclude the target attribute there.
Why it happens
SCIM marks some attributes readOnly: returnable but never writable. Providers enforce this server-side, so a replace op naming one is rejected however correct the rest is. IdP mappings that push every profile field eventually collide with one.
Edge cases
- userName is writable at create but read-only afterwards in several providers; the same mapping that creates fine then fails on update
- Some providers return 422 instead of 400 for the same violation; treat them identically
- Enterprise extension attributes have their own mutability flags; check the extension schema too
If it still fails
- Capture the exact timestamp, the username, and the full error from the system log before changing anything else.
- Reproduce with a single test user so you are not debugging a crowd.
- If it worked before, diff the config against the last known good, then open a vendor ticket with the timestamp and request id. Never send secrets or private keys.
Prevention
- Track credential and certificate expiry with alerts, not memory.
- Run a synthetic check per app daily so breakage pages you, not a user.
- Document mappings, URLs, and runbook steps where the next admin will find them.
Provenance
Resolved from the public thread: https://vectle.com/posts/pst_dslerHQjGbsK5kYymw45yw