{"record":{"id":"9b8f0129725cff92","repo":"passbolt/passbolt_api","slug":"could-not-delete-the-resource","errorCode":null,"errorMessage":"Could not delete the resource.","messagePattern":"Could not delete the resource\\.","errorType":"validation","errorClass":"ValidationException","httpStatus":422,"severity":"error","filePath":"src/Controller/Resources/ResourcesDeleteController.php","lineNumber":141,"sourceCode":"     */\n    protected function _handleDeleteError(Resource $resource): void\n    {\n        $errors = $resource->getErrors();\n        if (empty($errors)) {\n            return;\n        }\n        if (isset($errors['deleted']['is_not_soft_deleted'])) {\n            throw new NotFoundException(__('The resource does not exist.'));\n        }\n        if (isset($errors['id']['has_access'])) {\n            // If the user has a read access return a 403, otherwise return a 404 to avoid data leak.\n            $acoType = PermissionsTable::RESOURCE_ACO;\n            if ($this->Resources->Permissions->hasAccess($acoType, $resource->id, $this->User->id())) {\n                throw new ForbiddenException(__('You do not have the permission to delete this resource.'));\n            }\n            throw new NotFoundException(__('The resource does not exist.'));\n        }\n        throw new ValidationException(__('Could not delete the resource.'), $resource, $this->Resources);\n    }\n\n    /**\n     * Send email notification\n     *\n     * @param \\App\\Model\\Entity\\Resource $resource Resource\n     * @param \\Cake\\Datasource\\ResultSetInterface $users Users who had access to the resource, deleter excluded\n     * @return void\n     */\n    protected function _notifyUser(Resource $resource, ResultSetInterface $users): void\n    {\n        $event = new Event(static::DELETE_SUCCESS_EVENT_NAME, $this, [\n            'resource' => $resource,\n            'deletedBy' => $this->User->id(),\n            'users' => $users,\n        ]);\n        $this->getEventManager()->dispatch($event);\n    }","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/src/Controller/Resources/ResourcesDeleteController.php#L123-L159","documentation":"A 422 ValidationException raised by _handleDeleteError as the final fallback when softDelete() failed with validation errors that match neither the soft-deleted nor has_access rules. The exception carries the resource entity and ResourcesTable errors so clients can see which fields failed validation.","triggerScenarios":"DELETE /resources/{id}.json where a plugin-added or custom validation rule on the Resources entity fails during softDelete (any error key other than 'deleted.is_not_soft_deleted' or 'id.has_access').","commonSituations":"Custom plugins (e.g. metadata, folders) adding validation on resources, schema drift after an upgrade leaving fields in a state that fails rules, corrupted resource rows.","solutions":["Read the error details in the 422 response body — they name the failing field and rule.","Run pending migrations and clear cache to fix schema/plugin drift.","Disable recently added resource-related plugins to identify which rule fails.","Fix the offending resource data directly (e.g. via cake console) if a row is corrupted."],"exampleFix":"// before\nconst resp = await fetch(deleteUrl, {method: 'DELETE'});\nthrow new Error('delete failed');\n// after\nconst resp = await fetch(deleteUrl, {method: 'DELETE'});\nif (resp.status === 422) {\n  const body = await resp.json();\n  console.error('Validation errors:', body.errors); // field-level detail\n}","handlingStrategy":"try-catch","validationCode":"// surface the 422 error body to identify the failing field/rule before retrying\nconst resp = await fetch(`/resources/${id}.json`, {method: 'DELETE'});\nif (resp.status === 422) { const {errors} = await resp.json(); inspect(errors); }","typeGuard":null,"tryCatchPattern":"try { await api.delete(`/resources/${id}.json`); } catch (e) { if (e.status === 422) showFieldErrors(e.body.errors); else throw e; }","preventionTips":["Read the 422 response body — it names the failing field and rule","Keep plugins and migrations in sync across environments","Audit custom validation rules on Resources when upgrades change behavior"],"tags":["http-422","validation","resources","soft-delete"],"backgroundTag":"schema-validation-failed","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"}