{"record":{"id":"0b58c1108b3b7282","repo":"passbolt/passbolt_api","slug":"the-expiry-date-is-required","errorCode":null,"errorMessage":"The expiry date is required.","messagePattern":"The expiry date is required\\.","errorType":"validation","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"plugins/PassboltEe/PasswordExpiryPolicies/src/Service/Resources/PasswordExpiryPoliciesResourcesExpiryUpdateService.php","lineNumber":88,"sourceCode":"     * @throws \\Cake\\Http\\Exception\\BadRequestException if the expired value are not valid\n     * @throws \\Cake\\Http\\Exception\\BadRequestException if the resource_id value are not valid\n     * @throws \\Cake\\Http\\Exception\\BadRequestException if the resource_id value is found twice in the payload\n     * @throws \\Cake\\Http\\Exception\\BadRequestException if the sanitized array is empty\n     */\n    protected function validateAndParsePayload(array $data): array\n    {\n        $dataSanitized = [];\n        foreach ($data as $resource) {\n            if (!is_array($resource)) {\n                throw new BadRequestException(__('An array of arrays is expected.'));\n            }\n            $resourceId = $resource['id'] ?? null;\n            if (!Validation::uuid($resourceId)) {\n                throw new BadRequestException(__('The identifier should be a valid UUID.'));\n            }\n            $isExpiredDefined = array_key_exists('expired', $resource);\n            if (!$isExpiredDefined) {\n                throw new BadRequestException(__('The expiry date is required.'));\n            }\n            $expiryDate = $resource['expired'];\n            if (array_key_exists($resourceId, $dataSanitized)) {\n                throw new BadRequestException(__('The identifier should be unique: {0}.', $resourceId));\n            }\n            $dataSanitized[$resourceId] = is_null($expiryDate) ? $expiryDate : new DateTime($expiryDate);\n        }\n        if (empty($dataSanitized)) {\n            throw new BadRequestException(__('The data should not be empty.'));\n        }\n\n        return $dataSanitized;\n    }\n\n    /**\n     * @param \\App\\Utility\\UserAccessControl $uac UAC\n     * @param array $resourceIds the list of the resourceIds to update\n     * @return void","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltEe/PasswordExpiryPolicies/src/Service/Resources/PasswordExpiryPoliciesResourcesExpiryUpdateService.php#L70-L106","documentation":"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.","triggerScenarios":"Submitting data items like {\"id\": \"<uuid>\"} without the 'expired' key to the resources expiry update endpoint.","commonSituations":"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.","solutions":["Always include 'expired' in each item — use null explicitly to clear the expiry date","Pass a valid date string (e.g. '2026-12-31T00:00:00+00:00') to set an expiry","Update the client/integration to the current API contract for this endpoint"],"exampleFix":"// before\ndata: [{\"id\": \"8e3874ae-4b40-590b-968a-418f70bdbb85\"}]\n\n// after\ndata: [{\"id\": \"8e3874ae-4b40-590b-968a-418f70bdbb85\", \"expired\": null}] // or a date","handlingStrategy":"validation","validationCode":"foreach ($data as $i => $item) {\n    if (!array_key_exists('expired', $item)) {\n        throw new \\InvalidArgumentException(\"Item $i missing required 'expired' key\");\n    }\n}","typeGuard":"function hasExpiredKey(array $item): bool {\n    return array_key_exists('expired', $item);\n}","tryCatchPattern":"try {\n    $service->updateMany($uac, $data);\n} catch (BadRequestException $e) {\n    // inspect payload for missing 'expired' keys before retry\n}","preventionTips":["Always send the 'expired' key, even when clearing the date with null","Document the payload contract for API consumers","Add schema validation (JSON schema) on the client payload"],"tags":["passbolt","bad-request","validation","missing-field"],"backgroundTag":"empty-required-field","analyzedSha":"31c1bbc10f32808a607fa9bd81891e898779c0bc","analyzedAt":"2026-09-17T00:04:38.960Z","contentChangedAt":"2026-09-17T00:04:38.960Z","schemaVersion":2},"datasetVersion":"2026-09-21T09:17:21.228Z"}