{"record":{"id":"bbf71739d0cf52d2","repo":"passbolt/passbolt_api","slug":"the-user-cannot-be-deleted-because-its-the-sole-owner-of","errorCode":null,"errorMessage":"The user cannot be deleted because its the sole owner of shared content","messagePattern":"The user cannot be deleted because its the sole owner of shared content","errorType":"http","errorClass":"ConflictException","httpStatus":409,"severity":"error","filePath":"plugins/PassboltEe/Scim/src/Utility/Resource/UserScimResource.php","lineNumber":955,"sourceCode":"    {\n        if (!$this->userEntity) {\n            throw new ScimException(\n                sprintf(\n                    'The values of the %s resource has not been set for the `delete` operation',\n                    $this->getType()\n                )\n            );\n        }\n\n        $this->assertAdminDeleteAllowed();\n\n        try {\n            $result = $this->Users->softDelete($this->userEntity);\n            $errors = $this->userEntity->getErrors();\n            if (!$result || $errors !== []) {\n                if (isset($errors['id']['soleOwnerOfSharedContent'])) {\n                    // @todo: send email\n                    throw new ConflictException(\n                        'The user cannot be deleted because its the sole owner of shared content'\n                    );\n                }\n                throw new ConflictException('The User resource could not be deleted due to validation failure');\n            }\n        } catch (Exception $e) {\n            ScimLog::error(sprintf('Unable to delete the user with id `%s`', $this->userEntity->id));\n            ScimLog::error($e->getMessage());\n            ScimLog::error($e->getTraceAsString());\n\n            throw new ConflictException('Unexpected error when trying to delete the user.');\n        }\n\n        return $this;\n    }\n\n    /**\n     * @inheritDoc","sourceCodeStart":937,"sourceCodeEnd":973,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltEe/Scim/src/Utility/Resource/UserScimResource.php#L937-L973","documentation":"Raised in UserScimResource::delete() when the SCIM user deletion fails because the CakePHP Users table validation produced a 'soleOwnerOfSharedContent' error on the id field. Passbolt refuses to soft-delete a user who is the only owner of passwords/folders shared with others, since deletion would orphan shared content. It surfaces as an HTTP 409 Conflict on the SCIM /Users DELETE endpoint.","triggerScenarios":"DELETE /scim/v2.0/Users/{id} where the target user is the sole owner of folders/passwords shared with other users (e.g. an offboarded admin who shared credentials with the team and nobody else has ownership).","commonSituations":"IdP-driven SCIM deprovisioning (Okta, Azure AD) disabling/deleting a user; cleanup scripts deleting admins who created most shared items; automated offboarding without ownership transfer first.","solutions":["Before deleting, transfer ownership of the shared items: log in as another admin (or via API) and share/change owner of the user's personal folders and passwords with another user, then retry the DELETE.","Delete or reassign the shared resources via the passbolt UI/API so the user no longer solely owns shared content.","If business rules allow, disable the user instead of deleting (SCIM PATCH active=false) so content stays accessible.","Check the server error log / ScimLog for the exact validation errors to confirm the sole-owner condition."],"exampleFix":"// before (fails)\nDELETE /scim/v2.0/Users/8a4b...  // user owns shared folder alone\n// after: share the folder with another owner first, then\nDELETE /scim/v2.0/Users/8a4b...  // 204 No Content","handlingStrategy":"try-catch","validationCode":"// Before deleting via SCIM, check the user still exists\n$resp = $client->get(\"/scim/v2.0/Users/{$id}\");\nif ($resp->getStatusCode() !== 200) { return; } // already gone, nothing to do","typeGuard":null,"tryCatchPattern":"try {\n    $client->delete(\"/scim/v2.0/Users/{$id}\");\n} catch (ClientException $e) {\n    if ($e->getResponse()->getStatusCode() === 409\n        && str_contains((string)$e->getResponse()->getBody(), 'sole owner of shared content')) {\n        // transfer ownership then retry\n    } else { throw $e; }\n}","preventionTips":["Transfer/reassign ownership of shared folders and passwords before offboarding a user.","Prefer SCIM PATCH active=false (disable) over hard delete for users who own shared content.","Verify with an admin that the departing user is not the sole owner of team content.","Handle 409 as an expected offboarding outcome, not a bug."],"tags":["scim","user-deletion","conflict","ownership"],"backgroundTag":"invalid-state-transition","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"}