passbolt/passbolt_api · error · BadRequestException

The identifier should be a valid UUID.

Error message

The identifier should be a valid UUID.

What it means

In the bulk expiry update payload each resource entry must carry a 'id' field that is a valid UUID. validateAndParsePayload throws this BadRequestException when the id key is missing or fails CakePHP's Validation::uuid() check.

Solutions

  1. Supply a valid v4 UUID in each item's 'id' field
  2. Fetch real resource IDs from GET /resources.json first and use the 'id' field of each returned resource
  3. Trim whitespace and re-check for copy/paste corruption of the UUID

Example fix

// before
data: [{"id": "resource-123", "expired": "2026-01-01"}]

// after
data: [{"id": "8e3874ae-4b40-590b-968a-418f70bdbb85", "expired": "2026-01-01"}]
Defensive patterns

Strategy: validation

Validate before calling

foreach ($data as $item) {
    if (!isset($item['id']) || !\Cake\Validation\Validation::uuid($item['id'])) {
        throw new \InvalidArgumentException("Invalid resource id: " . json_encode($item['id'] ?? null));
    }
}

Type guard

function isUuid(mixed $id): bool {
    return is_string($id) && \Cake\Validation\Validation::uuid($id);
}

Try / catch

try {
    $service->updateMany($uac, $data);
} catch (BadRequestException $e) {
    if ($e->getMessage() === 'The identifier should be a valid UUID.') {
        // fix payload ids and retry
    }
}

Prevention

When it happens

Trigger: Payload items with no 'id' key, an empty id, or a malformed id like '123' or 'resource-1' submitted to the resources expiry update endpoint.

Common situations: Hardcoded test IDs; reading IDs from a spreadsheet/export that truncated or reformatted them; confusing resource IDs with folder or permission IDs.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17). Data as JSON: /api/errors/2c9c94ffb480b6ba. Report an issue: GitHub.

Appendix: source

Thrown at plugins/PassboltEe/PasswordExpiryPolicies/src/Service/Resources/PasswordExpiryPoliciesResourcesExpiryUpdateService.php:84

    /**
     * @param array $data payload
     * @return array<string, \Cake\I18n\DateTime|null> array with the resourceIds as keys and the expiry date as value
     * @throws \Cake\Http\Exception\BadRequestException if the expired value are not valid
     * @throws \Cake\Http\Exception\BadRequestException if the resource_id value are not valid
     * @throws \Cake\Http\Exception\BadRequestException if the resource_id value is found twice in the payload
     * @throws \Cake\Http\Exception\BadRequestException if the sanitized array is empty
     */
    protected function validateAndParsePayload(array $data): array
    {
        $dataSanitized = [];
        foreach ($data as $resource) {
            if (!is_array($resource)) {
                throw new BadRequestException(__('An array of arrays is expected.'));
            }
            $resourceId = $resource['id'] ?? null;
            if (!Validation::uuid($resourceId)) {
                throw new BadRequestException(__('The identifier should be a valid UUID.'));
            }
            $isExpiredDefined = array_key_exists('expired', $resource);
            if (!$isExpiredDefined) {
                throw new BadRequestException(__('The expiry date is required.'));
            }
            $expiryDate = $resource['expired'];
            if (array_key_exists($resourceId, $dataSanitized)) {
                throw new BadRequestException(__('The identifier should be unique: {0}.', $resourceId));
            }
            $dataSanitized[$resourceId] = is_null($expiryDate) ? $expiryDate : new DateTime($expiryDate);
        }
        if (empty($dataSanitized)) {
            throw new BadRequestException(__('The data should not be empty.'));
        }

        return $dataSanitized;
    }

View on GitHub (pinned to 31c1bbc10f)