{"record":{"id":"d463be57b0cafd44","repo":"passbolt/passbolt_api","slug":"invalid-data-to-create-a-scim-patch-request","errorCode":null,"errorMessage":"Invalid data to create a SCIM PATCH REQUEST","messagePattern":"Invalid data to create a SCIM PATCH REQUEST","errorType":"exception","errorClass":"Cake\\Http\\Exception\\BadRequestException","httpStatus":400,"severity":"error","filePath":"plugins/PassboltEe/Scim/src/Utility/Object/PatchRequest.php","lineNumber":65,"sourceCode":"        foreach ((array)$operations as $operationData) {\n            $this->operations[] = (new Operation())->setFromScim($operationData);\n        }\n\n        return $this;\n    }\n\n    /**\n     * @param array $data\n     * @return void\n     */\n    protected function validateScimData(array $data): void\n    {\n        $schemas = $data['schemas'] ?? [];\n        if (!in_array(SchemaIdentifier::API_PATCH_OPERATION, $schemas)) {\n            throw new BadRequestException('Invalid schema for SCIM PATCH REQUEST');\n        }\n        if (!array_key_exists('Operations', $data)) {\n            throw new BadRequestException('Invalid data to create a SCIM PATCH REQUEST');\n        }\n    }\n\n    /**\n     * @inheritDoc\n     */\n    public function toSCIM(): array\n    {\n        $data = [\n            'schemas' => [SchemaIdentifier::API_PATCH_OPERATION],\n            'Operations' => [],\n        ];\n        foreach ($this->operations as $operation) {\n            $data['Operations'][] = $operation->toSCIM();\n        }\n\n        return $data;\n    }","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltEe/Scim/src/Utility/Object/PatchRequest.php#L47-L83","documentation":"After the schema check passes, validateScimData requires the PATCH payload to contain an 'Operations' key holding the list of patch operations. Its absence means the request has a valid PatchOp schema declaration but no actual operations, so this BadRequestException is thrown.","triggerScenarios":"PATCH /scim/v2/Users/{id} or /Groups/{id} with a body containing 'schemas' with the PatchOp URN but no 'Operations' array (or misspelled key like 'operations').","commonSituations":"Case-sensitivity mistake ('operations' vs 'Operations'); client builds an empty patch and omits the key instead of sending an empty array; JSON serialization drops empty arrays.","solutions":["Include an 'Operations' key (array) in the PATCH body; use an empty array if there is truly nothing to change.","Fix key casing to exactly 'Operations' per RFC 7644.","Ensure your serializer does not drop empty arrays; send Operations: [] explicitly.","Log the decoded request body to confirm what actually reached the server."],"exampleFix":"// before\n{\"schemas\": [\"urn:ietf:params:scim:api:messages:2.0:PatchOp\"], \"operations\": []}\n// after\n{\"schemas\": [\"urn:ietf:params:scim:api:messages:2.0:PatchOp\"], \"Operations\": []}","handlingStrategy":"validation","validationCode":"if (!array_key_exists('Operations', $body)) {\n    throw new InvalidArgumentException('PATCH body must contain an Operations array');\n}","typeGuard":"function hasOperations(mixed $body): bool {\n    return is_array($body) && array_key_exists('Operations', $body)\n        && is_array($body['Operations']);\n}","tryCatchPattern":"try {\n    $patchRequest = PatchRequest::setFromScim($data);\n} catch (BadRequestException $e) {\n    // ensure key casing is 'Operations' and rebuild payload\n}","preventionTips":["Use exact key 'Operations' (capital O) per RFC 7644.","Send Operations: [] instead of omitting the key for empty patches.","Ensure serializers don't drop empty arrays.","Unit-test the PATCH envelope builder."],"tags":["scim","patch","missing-field"],"backgroundTag":"missing-required-argument","analyzedSha":"31c1bbc10f32808a607fa9bd81891e898779c0bc","analyzedAt":"2026-09-17T00:04:38.960Z","contentChangedAt":"2026-09-17T00:04:38.960Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}