passbolt/passbolt_api · error · InternalErrorException

The resource type could not be deleted.

Error message

The resource type could not be deleted.

What it means

Thrown by ResourceTypesDeleteService::delete() when the soft-delete save of the resource type entity fails (save() returns false). It means the 'resources of this type still exist' check passed but persisting the deleted timestamp failed, typically due to model validation or database errors. The InternalErrorException maps to HTTP 500.

Solutions

  1. Check the storage/logs error log and the table's rules (applicationRules) for why save() failed
  2. Run pending migrations (ddev refresh) to ensure the resource_types schema is current
  3. Verify database connectivity and that the row still exists before save
  4. Inspect ResourceTypesTable events (beforeSave/beforeRules) for conditions that block a soft delete

Example fix

// before
$resourceType->deleted = DateTime::now();
if (!$resourcesTypesTable->save($resourceType)) {
    throw new InternalErrorException(__('The resource type could not be deleted.'));
}
// after
$resourceType->deleted = DateTime::now();
$resourceType->setDirty('deleted', true);
$result = $resourcesTypesTable->save($resourceType, ['checkRules' => true]);
if (!$result) {
    Log::error('ResourceType delete failed', ['errors' => $resourceType->getErrors()]);
    throw new InternalErrorException(__('The resource type could not be deleted.'));
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (!Validation::uuid($resourceTypeId)) { throw new BadRequestException(__('The resource type identifier should be a UUID.')); }
$inUse = $resourcesTable->find()->where(['resource_type_id' => $resourceTypeId])->count();
if ($inUse > 0) { throw new BadRequestException(__('The resource type can not be deleted as resources of this type still exist.')); }

Try / catch

try {
    $service->delete($uac, $resourceTypeId);
} catch (BadRequestException $e) {
    // resources still exist or invalid id
} catch (InternalErrorException $e) {
    Log::error('Delete failed: ' . $resourceType->getErrors());
}

Prevention

When it happens

Trigger: Calling the resource type delete API (or the service directly) where $resourcesTypesTable->save($resourceType) returns false after $resourceType->deleted = DateTime::now() — e.g. a DB constraint violation, connection failure, or beforeSave/beforeDelete rules rejecting the save.

Common situations: Database down or migration missing (resource_types.deleted column absent); a behavioral rule or validation attached to ResourceTypesTable rejecting the modified entity; concurrency where another process already deleted the row; database permission issues.

Related errors


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

Appendix: source

Thrown at plugins/PassboltCe/ResourceTypes/src/Service/ResourceTypesDeleteService.php:85

        }
        if ($highlander->isTheOnlyOne($resourceType)) {
            throw new BadRequestException(__('You cannot delete the last resource type available.'));
        }

        /** @var \App\Model\Table\ResourcesTable $resourcesTable */
        $resourcesTable = $this->fetchTable('Resources');
        $count = $resourcesTable->find()->where([
            'resource_type_id' => $resourceTypeId,
            'deleted' => false,
        ])->all()->count();
        if ($count !== 0) {
            $msg = __('The resource type can not be deleted as resources of this type still exist.');
            throw new BadRequestException($msg);
        }

        $resourceType->deleted = DateTime::now();
        if (!$resourcesTypesTable->save($resourceType)) {
            throw new InternalErrorException(__('The resource type could not be deleted.'));
        }
    }

    /**
     * Undo soft delete a given resource type
     *
     * @param \App\Utility\UserAccessControl $uac user access control
     * @param string $resourceTypeId uuid
     * @return void
     * @throws \Cake\Http\Exception\BadRequestException if the resource type is not deleted
     * @throws \Cake\Http\Exception\NotFoundException if resource type is not present
     */
    public function undoDelete(UserAccessControl $uac, string $resourceTypeId): void
    {
        $uac->assertIsAdmin();

        if (!Validation::uuid($resourceTypeId)) {
            throw new BadRequestException(__('The resource type identifier should be a UUID.'));

View on GitHub (pinned to 31c1bbc10f)