passbolt/passbolt_api · error · ConflictException

The user cannot be deleted because its the sole owner of…

Error message

The user cannot be deleted because its the sole owner of shared content

What it means

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.

Solutions

  1. 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.
  2. Delete or reassign the shared resources via the passbolt UI/API so the user no longer solely owns shared content.
  3. If business rules allow, disable the user instead of deleting (SCIM PATCH active=false) so content stays accessible.
  4. Check the server error log / ScimLog for the exact validation errors to confirm the sole-owner condition.

Example fix

// before (fails)
DELETE /scim/v2.0/Users/8a4b...  // user owns shared folder alone
// after: share the folder with another owner first, then
DELETE /scim/v2.0/Users/8a4b...  // 204 No Content
Defensive patterns

Strategy: try-catch

Validate before calling

// Before deleting via SCIM, check the user still exists
$resp = $client->get("/scim/v2.0/Users/{$id}");
if ($resp->getStatusCode() !== 200) { return; } // already gone, nothing to do

Try / catch

try {
    $client->delete("/scim/v2.0/Users/{$id}");
} catch (ClientException $e) {
    if ($e->getResponse()->getStatusCode() === 409
        && str_contains((string)$e->getResponse()->getBody(), 'sole owner of shared content')) {
        // transfer ownership then retry
    } else { throw $e; }
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17). Data as JSON: /api/errors/bbf71739d0cf52d2. Report an issue: GitHub.

Appendix: source

Thrown at plugins/PassboltEe/Scim/src/Utility/Resource/UserScimResource.php:955

    {
        if (!$this->userEntity) {
            throw new ScimException(
                sprintf(
                    'The values of the %s resource has not been set for the `delete` operation',
                    $this->getType()
                )
            );
        }

        $this->assertAdminDeleteAllowed();

        try {
            $result = $this->Users->softDelete($this->userEntity);
            $errors = $this->userEntity->getErrors();
            if (!$result || $errors !== []) {
                if (isset($errors['id']['soleOwnerOfSharedContent'])) {
                    // @todo: send email
                    throw new ConflictException(
                        'The user cannot be deleted because its the sole owner of shared content'
                    );
                }
                throw new ConflictException('The User resource could not be deleted due to validation failure');
            }
        } catch (Exception $e) {
            ScimLog::error(sprintf('Unable to delete the user with id `%s`', $this->userEntity->id));
            ScimLog::error($e->getMessage());
            ScimLog::error($e->getTraceAsString());

            throw new ConflictException('Unexpected error when trying to delete the user.');
        }

        return $this;
    }

    /**
     * @inheritDoc

View on GitHub (pinned to 31c1bbc10f)