{"record":{"id":"b1cf6e29189567b8","repo":"passbolt/passbolt_api","slug":"could-not-save-permission-history","errorCode":null,"errorMessage":"Could not save permission history.","messagePattern":"Could not save permission history\\.","errorType":"exception","errorClass":"InternalErrorException","httpStatus":500,"severity":"error","filePath":"plugins/PassboltCe/Log/src/Model/Table/PermissionsHistoryTable.php","lineNumber":212,"sourceCode":"     */\n    public function create(array $data): PermissionHistory\n    {\n        // Check validation rules.\n        $log = $this->buildEntity($data);\n        if ($log->getErrors()) {\n            throw new ValidationException(__('Could not validate permission history data.', true), $log, $this);\n        }\n\n        $permissionHistory = $this->save($log);\n\n        // Check for validation errors. (associated models too).\n        if ($log->getErrors()) {\n            throw new ValidationException(__('Could not validate permission history data.'), $permissionHistory, $this);\n        }\n\n        // Check for errors while saving.\n        if (!$permissionHistory) {\n            throw new InternalErrorException('Could not save permission history.');\n        }\n\n        return $permissionHistory;\n    }\n}\n","sourceCodeStart":194,"sourceCodeEnd":218,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltCe/Log/src/Model/Table/PermissionsHistoryTable.php#L194-L218","documentation":"Thrown by PermissionsHistoryTable::create() when CakePHP's save() returns false for a permission_history record that already passed validation. It signals an unexpected persistence failure (database constraint, connection, or afterSave rule) rather than bad input, so it surfaces as a 500 InternalErrorException.","triggerScenarios":"Calling PermissionsHistoryTable::create($data) where the entity validates but $this->save($log) returns falsy — e.g. a database-level constraint violation (duplicate/missing aco_foreign_key or aro_foreign_key not present in aco/aro tables), storage engine failure, or an event listener aborting the save.","commonSituations":"Orphaned permission data after a hard delete (permissions referencing deleted resources/users), missing or broken permissions_history table after a skipped migration, database disk-full or lock issues, and plugin (Passbolt/Log) schema drift between versions.","solutions":["Verify the referenced aco_foreign_key and aro_foreign_key exist in their parent tables before calling create()","Run pending migrations (passbolt migrate) and confirm the permissions_history table exists with correct columns","Check the database error log / CakePHP error.log for the underlying SQL failure and fix the constraint","Re-run the permission change transaction; if transient (lock/timeout), retry after the DB recovers"],"exampleFix":"// before\n$permissionHistory = $this->PermissionsHistory->create($data); // throws 500 on save failure\n// after\n$aco = $this->Aco->findById($data['aco_foreign_key'])->first();\n$aro = $this->Aro->findById($data['aro_foreign_key'])->first();\nif (!$aco || !$aro) {\n    throw new BadRequestException(__('Referenced aco/aro does not exist.'));\n}\n$permissionHistory = $this->PermissionsHistory->create($data);","handlingStrategy":"try-catch","validationCode":"use Cake\\Validation\\Validation;\n$ok = Validation::uuid($data['aco_foreign_key'] ?? '') && Validation::uuid($data['aro_foreign_key'] ?? '');","typeGuard":"if (!is_array($data) || empty($data['aco_foreign_key']) || empty($data['aro_foreign_key'])) { return false; }","tryCatchPattern":"try {\n    $log = $this->PermissionsHistory->create($data);\n} catch (\\Cake\\Http\\Exception\\InternalErrorException $e) {\n    $this->log('Permission history save failed: ' . $e->getMessage());\n    // inspect DB logs, retry or surface a 500 with context\n}","preventionTips":["Always run migrations (passbolt migrate) after plugin upgrades","Ensure aco/aro parent rows exist before writing permission history","Wrap permission changes and their history writes in a DB transaction","Monitor database error logs for constraint violations on permissions_history"],"tags":["database","persistence","orm"],"backgroundTag":"database-write-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"}