passbolt/passbolt_api · error · BadRequestException

The expiry date is required.

Error message

The expiry date is required.

What it means

Each entry in the bulk expiry update payload must contain an 'expired' key (the value may be null to clear the expiry date). validateAndParsePayload throws this BadRequestException when the 'expired' key is entirely absent from an item, since the operation cannot know the intended expiry state.

Solutions

  1. Always include 'expired' in each item — use null explicitly to clear the expiry date
  2. Pass a valid date string (e.g. '2026-12-31T00:00:00+00:00') to set an expiry
  3. Update the client/integration to the current API contract for this endpoint

Example fix

// before
data: [{"id": "8e3874ae-4b40-590b-968a-418f70bdbb85"}]

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

Strategy: validation

Validate before calling

foreach ($data as $i => $item) {
    if (!array_key_exists('expired', $item)) {
        throw new \InvalidArgumentException("Item $i missing required 'expired' key");
    }
}

Type guard

function hasExpiredKey(array $item): bool {
    return array_key_exists('expired', $item);
}

Try / catch

try {
    $service->updateMany($uac, $data);
} catch (BadRequestException $e) {
    // inspect payload for missing 'expired' keys before retry
}

Prevention

When it happens

Trigger: Submitting data items like {"id": "<uuid>"} without the 'expired' key to the resources expiry update endpoint.

Common situations: Clients assuming omitting 'expired' means 'leave unchanged' (the API requires the key even to clear the date with null); older client versions predating the expired field requirement.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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

Appendix: source

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

     * @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;
    }

    /**
     * @param \App\Utility\UserAccessControl $uac UAC
     * @param array $resourceIds the list of the resourceIds to update
     * @return void

View on GitHub (pinned to 31c1bbc10f)