{"record":{"id":"c3572e04969ac782","repo":"passbolt/passbolt_api","slug":"the-metadata-private-key-data-must-be-an-array","errorCode":null,"errorMessage":"The metadata private key data must be an array.","messagePattern":"The metadata private key data must be an array\\.","errorType":"validation","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"plugins/PassboltCe/Metadata/src/Model/Dto/MetadataPrivateKeysCreateManyDto.php","lineNumber":36,"sourceCode":"\nuse Cake\\Http\\Exception\\BadRequestException;\n\nclass MetadataPrivateKeysCreateManyDto\n{\n    /**\n     * @var array\n     */\n    private array $data = [];\n\n    /**\n     * @param array $requestData Request data to convert into DTO.\n     * @return void\n     */\n    public function __construct(array $requestData)\n    {\n        foreach ($requestData as $data) {\n            if (!is_array($data)) {\n                throw new BadRequestException(__('The metadata private key data must be an array.'));\n            }\n\n            $this->data[] = [\n                'metadata_key_id' => $data['metadata_key_id'] ?? null,\n                'user_id' => $data['user_id'] ?? null,\n                'data' => $data['data'] ?? null,\n            ];\n        }\n    }\n\n    /**\n     * @return array\n     */\n    public function getData(): array\n    {\n        return $this->data;\n    }\n}","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltCe/Metadata/src/Model/Dto/MetadataPrivateKeysCreateManyDto.php#L18-L54","documentation":"MetadataPrivateKeysCreateManyDto's constructor iterates the request data and requires every element to be an array (one metadata-private-key entry per user). If any element is a scalar or null, it throws this BadRequestException. It guards against malformed batch payloads when metadata private keys are shared with users.","triggerScenarios":"Calls that build MetadataPrivateKeysCreateManyDto (metadata private keys create-many endpoints) passing a payload where an entry under the collection key is a string, integer, or null instead of an associative array with metadata_key_id/user_id/data keys.","commonSituations":"Client sends the private keys object itself instead of an array of objects (e.g. {\"0\": {...}} vs. a single object); JSON bodies where a list element is omitted and defaults to null; integration scripts hand-building the payload with wrong nesting.","solutions":["Ensure the request data is a numerically indexed array where every element is an associative array containing metadata_key_id, user_id, and data.","Validate/normalize the payload client-side before the call, rejecting or skipping non-array entries.","Check the JSON body nesting: it must be a list of objects, not a single object or scalar.","Wrap the DTO construction and surface a clear 400 message indicating which entry index was malformed."],"exampleFix":"// before\n{\"metadata_key_id\": \"<uuid>\", \"user_id\": \"<uuid>\", \"data\": \"<armored>\"}\n\n// after\n[{\"metadata_key_id\": \"<uuid>\", \"user_id\": \"<uuid>\", \"data\": \"<armored>\"}]","handlingStrategy":"validation","validationCode":"$privateKeys = $requestData['metadata_private_keys'] ?? [];\nif (!is_array($privateKeys) || empty($privateKeys)) {\n    throw new InvalidArgumentException('metadata_private_keys must be a non-empty list');\n}\nforeach ($privateKeys as $i => $entry) {\n    if (!is_array($entry)) {\n        throw new InvalidArgumentException(\"Entry $i must be an array\");\n    }\n}","typeGuard":"function isMetadataPrivateKeyList(mixed $v): bool {\n    return is_array($v) && array_reduce($v, fn($ok, $e) => $ok && is_array($e), true);\n}","tryCatchPattern":"try {\n    $dto = new MetadataPrivateKeysCreateManyDto($requestData);\n} catch (BadRequestException $e) {\n    return $this->getResponse()->withStatus(400, 'Each metadata private key entry must be an object');\n}","preventionTips":["Always wrap single entries in a list: [{...}]","Validate payload shape with JSON Schema before sending","Check for null elements caused by default JSON encoding of empty values","Test integrations against the API with representative batch payloads"],"tags":["passbolt","api","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"}