The case that motivated this page: Microsoft documents a group member removal sent as {"op":"Remove","path":"members","value":[{"value":"..."}]}. Read literally, RFC 7644 section 3.5.2.2 removes the attribute and all its values, and no remove rule reads a value member. Microsoft's own known-issues page calls that request shape non SCIM compliant, lists the fix as not done, and its SCIM tutorial still prints it as the Remove Members example. Each side follows its own published document. Load the first preset to see both results side by side.
Input
Result
Nothing evaluated yet.
How to read the result
Literal RFC 7644. Each operation is applied in order, the result of one feeding the next (RFC 7644 3.5.2), under the bullets of 3.5.2.1 (add), 3.5.2.2 (remove) and 3.5.2.3 (replace), against a schema table derived from RFC 7643. Every step shows the op as received, the normalised op, the resolved target, the section and bullet applied, and the before and after difference. The first failing operation stops the request: the verdict is HTTP 400 with its scimType, and the ORIGINAL resource is shown, because 3.5.2 says a PATCH request "SHALL be treated as atomic" and "the original SCIM resource MUST be restored".
Sender's documented intent (Microsoft Learn). This column appears only for four request shapes Microsoft documents: (i) remove with path members and a value array listing members, (ii) replace of active with the string "False", (iii) a no-path replace whose value keys are dotted (name.givenName) or fully qualified with a schema URN, and (iv) op values written Add, Replace or Remove. It never appears for any other shape. In particular Microsoft's pages document no intent for an add with a filtered path, so none is invented here.
Where the RFC text gives two readings
- Dotted or URN-qualified keys in a no-path value. Reading A: the keys of the value object are attribute names, and the RFC 7643 2.1 ATTRNAME rule (a letter, then letters, digits,
$,-or_) has no., soname.givenNameis not an attribute name. Reading B: RFC 7644 3.10 says "All operations share a common scheme for referencing simple and complex attributes", written{urn}:{Attribute name}.{Sub-Attribute name}. Both are shown; the shape is not labelled invalid. This tool carries reading B forward. Microsoft's sample with these keys is the one it labels SCIM Compliant (the with-feature-flag sample). - Boolean sent as the string "False". RFC 7643 2.3 Table 1 maps Boolean to the RFC 7159 section 3 literal, and the JSON value arrived as a string, so the literal result is 400
invalidValue(RFC 7644 3.12, "not compatible with the operation or attribute type"). RFC 7643 2.3.2 also says "A boolean has no case sensitivity or uniqueness.", and that sentence is sometimes read as permitting it. - Remove with a filter that matches nothing. Default: no change, success, citing 3.5.2.2: "If the user was not a member of this group, no changes should be made to the resource, and a success response should be returned." The 3.12
noTargetdescription, "This occurs when the specified "path" value contains a filter that yields no match", can be read to apply. - Replace with a filter when the attribute is entirely absent. Bullet 4 (treat as add, which then meets the undefined filtered add) and bullet 8 (400
noTarget) conflict. Both are shown; bullet 8 is carried forward. - op case. RFC 7644 3.5.2 says op "MAY be one of "add", "remove", or "replace"" and states no case rule. The case-insensitivity in RFC 7643 2.1 covers ABNF strings, and op values are given in prose, not ABNF. Microsoft's tutorial says: "Don't require a case-sensitive match on structural elements in SCIM, in particular PATCH op operation values, as defined in section 3.5.2." Section 3.5.2 contains no such statement. By default this tool evaluates op case-insensitively and flags anything other than the three listed literals. The strict toggle rejects instead, without naming a
scimType, because RFC 7644 names none for this case. - Merges. Add on a complex single-valued attribute merges sub-attributes (bullet 3); bullets 3 and 7 also admit replacing the whole value. Replace through a matching filter replaces each matched record whole (bullet 6); bullet 5's merge wording can be read to apply. Both notes appear on the step.
Named refusals
- A value path nested inside a value filter, such as
emails[type eq "work" and x[y eq "z"]]: the Figure 1 ABNF admits it throughlogExpandFILTER, erratum 4690 (Held for Document Update) says that recursion is unintended, and its semantics are undefined. Result: 400invalidFilter, not evaluated. - A bare attribute expression used as a PATCH path, such as
schemas eq "urn:...": Figure 7 (PATH = attrPath / valuePath [subAttr]) does not allow it, and erratum 7122 (Held for Document Update) proposes allowing it. Result: 400invalidPath. - An unknown operator, such as
regex: 400invalidFilter(3.4.2.2, "Providers MUST decline to filter results if the specified filter operation is not recognized"). - An add whose path carries a filter: RFC 7644 3.5.2.1 has no rule for it. The step is shown as UNDEFINED, is not applied, and the verdict says it depends on an undefined step. Erratum 8097 (Held for Document Update) raises exactly this case.
Choices this tool makes where the text is silent
- Filter precedence is attribute expression, then
not, thenand, thenor. The printed 3.4.2.2 text lists "Grouping operators", "Logical operators", "Attribute operators" in that order of precedence; erratum 4670 (Held for Document Update) says that order is reversed, and every example in the RFC needs attribute expressions to bind tightest. This tool follows the erratum reading. notmust have a parenthesised operand, with optional whitespace before(, because the RFC's own example has a space; erratum 7319 (Reported) raises it.- Attribute names, sub-attribute names, schema URNs, attribute operators and
and,or,notmatch case-insensitively (3.4.2.2, 3.10, RFC 7643 2.1). JSON keys in the resource match case-insensitively too; the existing key's spelling is kept on write, and the schema's spelling is used when a key is created. Two keys that differ only in case are flagged as ambiguous. - String comparison follows
caseExact(3.4.2.2). For a case-insensitive attribute both sides are lower-cased with JavaScripttoLowerCase; full Unicode case folding is not applied. Reference and binary values compare exactly (RFC 7643 2.3.6 and 2.3.7).members.valuehascaseExactfalse in RFC 7643 8.7.1, somembers[value eq "ABC"]matches"abc". nematches an unassigned attribute;eq nullmatches only an unassigned or null value;co,swandewmatch string values only.- Removing an attribute that is already unassigned is reported as no change. A complex value left with no sub-attributes is dropped as unassigned.
- A sub-attribute path under a multi-valued attribute without a filter (for example
emails.value) has no rule in 3.5.2 and is reported as undefined. - When one value gets
primarytrue, values carryingprimarytrue are set to false; values without aprimarymember already read as false (RFC 7643 2.4). - Duplicate keys in one JSON object are flagged. The last one is used, as
JSON.parsewould; a duplicateopfails the request (3.5.2, "exactly one "op" member"). - A malformed request body (no PatchOp URN in
schemas, noOperationsarray) gets HTTP 400 without ascimType: Table 9'sinvalidSyntaxdescribes it but does not list PATCH.
Embedded schema table
Derived from the RFC 7643 8.7.1 schema representation and RFC 7643 3.1, then corrected by the errata below. Defaults from RFC 7643 2.2 apply where a cell is blank: not required, caseExact false, readWrite. This is a table written for this page, not the RFC's figure. An attribute not in this table is applied with its shape inferred from the JSON (an array means multi-valued) and flagged as "not in the core schemas; a custom schema may define it".
Show the table
| Schema | Attribute | Type | Multi | Required | caseExact | Mutability | Note |
|---|
Errata this page relies on
Statuses as re-read on 2026-10-01 from https://www.rfc-editor.org/errata_search.php?rfc=7644 and https://www.rfc-editor.org/errata_search.php?rfc=7643. Statuses change; re-check before you cite one.
| ID | RFC | Status | What it says | How this page uses it |
|---|---|---|---|---|
| 4670 | 7644 3.4.2.2 | Held for Document Update | The filter precedence order is reversed: attribute operators should bind before logical operators. | Parser precedence: attribute expression, not, and, or. |
| 4690 | 7644 3.4.2.2 | Held for Document Update | valFilter recursion through logExp is unintended; a value path should not nest inside a value filter. | Named refusal, 400 invalidFilter. |
| 7122 | 7644 3.5.2 | Held for Document Update | Proposes adding attrExp to the PATCH PATH rule. | Named refusal of a bare attrExp path, 400 invalidPath, with the proposal shown. |
| 7319 | 7644 3.4.2.2 | Reported | The ABNF allows no space after not, while the RFC's example has one. | Optional whitespace accepted between not and the parenthesis. |
| 8097 | 7644 3.5.2.1 | Held for Document Update | Raises an add whose path carries a filter, which the add rules do not cover. | Filtered add is shown as UNDEFINED and not applied. |
| 5368 | 7643 8.7.1 | Verified | Group displayName is required true; the figure said false while the 4.2 prose says REQUIRED. | displayName is required, so removing it is 400 mutability. |
| 6011 | 7643 8.7.1 | Reported | Asks for a display sub-attribute in the members definition. | members.display accepted and flagged informationally. |
| 8471 | 7643 8.7.1 | Verified | groups.$ref referenceTypes should be Group only. | Schema table. |
| 8472 | 7643 8.7.1 | Verified | Enterprise manager.value is caseExact true. | manager.value comparisons are case exact. |
Sources
All re-read on 2026-10-01. URLs are printed as text so the page never loads anything.
- RFC 7644, SCIM Protocol, September 2015: https://www.rfc-editor.org/rfc/rfc7644.txt (sections 3.4.2.2, 3.5.2, 3.5.2.1, 3.5.2.2, 3.5.2.3, 3.10, 3.12).
- RFC 7643, SCIM Core Schema, September 2015: https://www.rfc-editor.org/rfc/rfc7643.txt (sections 2.1 to 2.5, 3.1, 4.2, 4.3, 8.7.1).
- RFC 9865 (October 2025) and RFC 9967 (May 2026) both carry "Updates: 7643, 7644". RFC 9865 adds cursor-based pagination. RFC 9967 adds SCIM security events and an optional asynchronous request mode, in which a client sends
Prefer: respond-asyncand a server may answer 202 with no body. Neither changes how PATCH operations are applied under 3.5.2. https://www.rfc-editor.org/rfc/rfc9865.txt and https://www.rfc-editor.org/rfc/rfc9967.txt - Microsoft Learn, "Known issues and resolutions with SCIM 2.0 protocol compliance of the Microsoft Entra user provisioning service", visible "Last updated on" 2025-08-25: https://learn.microsoft.com/en-us/entra/identity/app-provisioning/application-provisioning-config-problem-scim-compatibility. Its table row "Update PATCH behavior to ensure compliance (such as active as boolean and proper group membership removals)" reads Fixed: No, Fix date: TBD, Backwards compatibility: use feature flag. The flag
aadOptscim062020, labelled "URL (SCIM Compliant)", changes four request shapes: requests made to disable users, requests to add a single-value string attribute, requests to replace multiple attributes, and requests to remove a group member. The page adds: "Note this feature flag currently doesn't work with on-demand provisioning." It namesAzureAdScimPatch2017as the URL to "roll back to the old, non SCIM compliant behavior". - Microsoft Learn, "Tutorial: Develop and plan provisioning for a SCIM endpoint in Microsoft Entra ID", visible "Last updated on" 2026-09-15: https://learn.microsoft.com/en-us/entra/identity/app-provisioning/use-scim-to-provision-users-and-groups. It says "Microsoft Entra ID emits the values of op as Add, Replace, and Remove." and prints "Update Group [Remove Members]" with path
membersand avaluearray.
This is an independent tool. It is not affiliated with or endorsed by Microsoft or the IETF. Microsoft Entra is named only to describe request shapes Microsoft publishes. Behaviour was reimplemented from RFC 7643 and RFC 7644; no code is reproduced. Preset request structures follow the cited Microsoft Learn samples with original identifiers and values.
Self test
Runs on load and on demand, against the same code that evaluated your request. It covers one fixture per bullet of 3.5.2.1, 3.5.2.2 and 3.5.2.3, every preset, the URN, quoting, case and caseExact fixtures, the named refusals, a precedence fuzz against an independent oracle (seeded random boolean trees over and, or and not, printed with minimal parentheses, parsed back and compared on random records), and a positive control: an assertion written to fail. If the control ever reports PASS, the suite is not running and its counts mean nothing.
Not run yet.
Show every check
| Check | Expected | Got | Result |
|---|