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
- Check the storage/logs error log and the table's rules (applicationRules) for why save() failed
- Run pending migrations (ddev refresh) to ensure the resource_types schema is current
- Verify database connectivity and that the row still exists before save
- 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
- Pre-check that no resources reference the type before deleting
- Keep resource_types schema migrated (run ddev refresh)
- Log entity errors when save() returns false
- Avoid disabling ORM transaction handling on the table
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
- Could not save the UI action, try again later.
- Could not parse the self registration settings found in…
- Could not save secret revision
- Could not save the action.
- Could not save the action log.
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)