{"record":{"id":"44cfcaaeafaae119","repo":"passbolt/passbolt_api","slug":"the-entity-must-be-an-array","errorCode":null,"errorMessage":"The entity must be an array.","messagePattern":"The entity must be an array\\.","errorType":"validation","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"plugins/PassboltCe/Metadata/src/Model/Validation/MetadataBatchUpdateValidationService.php","lineNumber":57,"sourceCode":"    /**\n     * Get the validation form\n     *\n     * @return \\Passbolt\\Metadata\\Form\\Upgrade\\MetadataBatchUpgradeForm\n     */\n    abstract public function getForm(): MetadataBatchUpgradeForm;\n\n    /**\n     * @param array $requestData Request data.\n     * @return array\n     * @throws \\Cake\\Http\\Exception\\BadRequestException If data is invalid.\n     * @throws \\App\\Error\\Exception\\CustomValidationException If data is invalid.\n     * @throws \\Cake\\Http\\Exception\\NotFoundException If one or more resources are not found.\n     */\n    public function validateMany(array $requestData): array\n    {\n        foreach ($requestData as $values) {\n            if (!is_array($values)) {\n                throw new BadRequestException(__('The entity must be an array.'));\n            }\n\n            $id = $values['id'] ?? null;\n            if (!Validation::uuid($id)) {\n                throw new BadRequestException(__('The identifier should be a valid UUID.'));\n            }\n        }\n\n        $entityIds = Hash::extract($requestData, '{n}.id');\n        $this->entities = $this->queryEntitiesFromIds($entityIds)->all()->toArray();\n        // Re-arrange entities array to set key as identifier and value as entity object to easily find it\n        $this->entities = Hash::combine($this->entities, '{n}.id', '{n}');\n\n        $data = [];\n        $errors = [];\n        foreach ($requestData as $i => $entity) {\n            $entityId = $entity['id'];\n            if (!array_key_exists($entityId, $this->entities)) {","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltCe/Metadata/src/Model/Validation/MetadataBatchUpdateValidationService.php#L39-L75","documentation":"MetadataBatchUpdateValidationService::validateMany processes batch metadata update payloads and requires every entry in the request array to be an associative array (an entity object with at least an `id`). If any element is a scalar or null, it throws this BadRequestException. It is the first guard of the batch update validation pipeline.","triggerScenarios":"Batch metadata update endpoints (e.g. PUT /metadata/resources or /metadata/folders batch) receiving a request array where an element is a string/number/null instead of an object like {\"id\": \"<uuid>\", ...}; calling validateMany directly with malformed arrays.","commonSituations":"Clients sending a flat list of ID strings instead of objects; JSON payloads where one row was serialized incorrectly; automation scripts building the batch list by joining IDs rather than objects.","solutions":["Send each batch entry as an object containing at least the `id` key: [{\"id\": \"<uuid>\", ...}, ...].","Validate the payload shape client-side, ensuring every element is_array before the request.","Fix JSON serialization so no element collapses to a scalar/null (e.g. empty objects encoded as empty arrays or null).","Wrap validateMany and return a 400 identifying the offending index to callers."],"exampleFix":"// before\n[\"<uuid-1>\", \"<uuid-2>\"]\n\n// after\n[{\"id\": \"<uuid-1>\", \"metadata_key_id\": \"<key-uuid>\"}, {\"id\": \"<uuid-2>\", \"metadata_key_id\": \"<key-uuid>\"}]","handlingStrategy":"validation","validationCode":"if (!is_array($batch)) {\n    throw new InvalidArgumentException('Batch body must be a list');\n}\nforeach ($batch as $i => $entry) {\n    if (!is_array($entry) || !isset($entry['id'])) {\n        throw new InvalidArgumentException(\"Batch entry $i must be an object with an id\");\n    }\n}","typeGuard":"function isBatchEntityList(mixed $v): bool {\n    return is_array($v) && array_reduce($v, fn($ok, $e) => $ok && is_array($e) && isset($e['id']), true);\n}","tryCatchPattern":"try {\n    $data = $service->validateMany($requestData);\n} catch (BadRequestException $e) {\n    return $this->getResponse()->withStatus(400, 'Each batch entry must be an object');\n}","preventionTips":["Send objects, not bare ID strings, in batch update payloads","Guard against JSON nulls/empty arrays entering the batch list","Add a schema check on the client that rejects scalar batch elements","Log the offending element index server-side for easier debugging"],"tags":["passbolt","batch-update","bad-request","type-mismatch","payload-validation"],"backgroundTag":"type-mismatch","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"}