passbolt/passbolt_api · error · BadRequestException
The metadata private key data must be an array.
Error message
The metadata private key data must be an array.
What it means
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.
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.
Example fix
// before
{"metadata_key_id": "<uuid>", "user_id": "<uuid>", "data": "<armored>"}
// after
[{"metadata_key_id": "<uuid>", "user_id": "<uuid>", "data": "<armored>"}] Defensive patterns
Strategy: validation
Validate before calling
$privateKeys = $requestData['metadata_private_keys'] ?? [];
if (!is_array($privateKeys) || empty($privateKeys)) {
throw new InvalidArgumentException('metadata_private_keys must be a non-empty list');
}
foreach ($privateKeys as $i => $entry) {
if (!is_array($entry)) {
throw new InvalidArgumentException("Entry $i must be an array");
}
} Type guard
function isMetadataPrivateKeyList(mixed $v): bool {
return is_array($v) && array_reduce($v, fn($ok, $e) => $ok && is_array($e), true);
} Try / catch
try {
$dto = new MetadataPrivateKeysCreateManyDto($requestData);
} catch (BadRequestException $e) {
return $this->getResponse()->withStatus(400, 'Each metadata private key entry must be an object');
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- The entity must be an array.
- V4 related fields are not supported for V5.
- V4 related fields are not supported for V5.
- An array of arrays is expected.
- Few fields are missing for the V5.
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/c3572e04969ac782.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltCe/Metadata/src/Model/Dto/MetadataPrivateKeysCreateManyDto.php:36
use Cake\Http\Exception\BadRequestException;
class MetadataPrivateKeysCreateManyDto
{
/**
* @var array
*/
private array $data = [];
/**
* @param array $requestData Request data to convert into DTO.
* @return void
*/
public function __construct(array $requestData)
{
foreach ($requestData as $data) {
if (!is_array($data)) {
throw new BadRequestException(__('The metadata private key data must be an array.'));
}
$this->data[] = [
'metadata_key_id' => $data['metadata_key_id'] ?? null,
'user_id' => $data['user_id'] ?? null,
'data' => $data['data'] ?? null,
];
}
}
/**
* @return array
*/
public function getData(): array
{
return $this->data;
}
}View on GitHub (pinned to 31c1bbc10f)