{"record":{"id":"f34442455fb9b4e7","repo":"passbolt/passbolt_api","slug":"the-permissions-data-array-keys-must-be-integers","errorCode":null,"errorMessage":"The permissions data array keys must be integers.","messagePattern":"The permissions data array keys must be integers\\.","errorType":"http","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"src/Service/Permissions/PermissionsUpdatePermissionsService.php","lineNumber":81,"sourceCode":"     * @param array|null $data The permissions to update\n     * @return \\App\\Model\\Dto\\EntitiesChangesDto\n     * @throws \\Cake\\Http\\Exception\\BadRequestException If the permissions passed\n     * @throws \\Exception If something unexpected occurred\n     */\n    public function updatePermissions(\n        UserAccessControl $uac,\n        string $aco,\n        string $acoForeignkey,\n        ?array $data = []\n    ): EntitiesChangesDto {\n        $entitiesChanges = new EntitiesChangesDto();\n\n        foreach ($data as $rowIndex => $row) {\n            if (!is_array($row)) {\n                throw new BadRequestException(__('The permissions data must be an array.'));\n            }\n            if (!is_int($rowIndex)) {\n                throw new BadRequestException(__('The permissions data array keys must be integers.'));\n            }\n            $permissionId = Hash::get($row, 'id', null);\n\n            // A new permission is provided when no id is found in the raw data.\n            if (is_null($permissionId)) {\n                $permission = $this->addPermission($uac, $rowIndex, $aco, $acoForeignkey, $row);\n                $entitiesChanges->pushAddedEntity($permission);\n            } else {\n                // If a property delete is found and set to true, then delete the permission.\n                // Otherwise update it.\n                $permission = $this->getPermission($rowIndex, $acoForeignkey, $permissionId);\n                $delete = Hash::get($row, 'delete');\n                if ($delete) {\n                    $permission = $this->deletePermission($permission);\n                    $entitiesChanges->pushDeletedEntity($permission);\n                } else {\n                    $permission = $this->updatePermission($uac, $rowIndex, $permission, $row);\n                    $entitiesChanges->pushUpdatedEntity($permission);","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/src/Service/Permissions/PermissionsUpdatePermissionsService.php#L63-L99","documentation":"Thrown by PermissionsUpdatePermissionsService::updatePermissions when the permissions payload passed to PUT /permissions/{aco} has array keys that are not integers. Each permissions row must be keyed by an integer index (new permissions) or an existing permission id position so the service can diff add/update/delete operations deterministically. String keys (e.g. from JSON objects or un-serialized payloads) are rejected with 400.","triggerScenarios":"Sending permissions data as an associative array with string keys (e.g. ['perm-0' => [...]] or a JSON object keyed by permission id) instead of a sequential integer-indexed array; passing a decoded JSON object where an array is expected.","commonSituations":"Client SDKs or scripts building the payload as an object/map instead of a list; PHP json_decode with assoc on an object-shaped permissions payload; upstream refactors that wrap rows in named keys.","solutions":["Ensure the permissions data is a zero-indexed integer array, e.g. array_values($data) before sending.","Send permissions as a JSON array [ {...}, {...} ] not an object { \"0\": {...} }.","If rows must be addressed by id, put the id inside each row ('id' key), not as the array key.","On the client, cast keys: $data = array_values($data); or json_encode(array_values(...))"],"exampleFix":"// before\n$data = ['perm-1' => ['type' => 15, 'aro_foreign_key' => '...']];\n// after\n$data = [['id' => 'perm-uuid', 'type' => 15, 'aro_foreign_key' => '...']];","handlingStrategy":"validation","validationCode":"if (!is_array($data) || array_keys($data) !== range(0, count($data) - 1)) { throw new \\InvalidArgumentException('permissions data must be integer-indexed'); }","typeGuard":"function isIntIndexedArray(mixed $data): bool { return is_array($data) && array_is_list($data); }","tryCatchPattern":null,"preventionTips":["Build payload as a list (array_values) before sending","Send JSON arrays, not objects, for permissions data","Put permission ids inside rows, not as keys"],"tags":["permissions","bad-request","payload-validation","php"],"backgroundTag":"invalid-argument-format","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"}