passbolt/passbolt_api · error · CustomValidationException
Could not save secret revision
Error message
Could not save secret revision
What it means
Thrown by CreateSecretRevisionsService::createFirstRevision() when SecretRevisions->save($secretRevision) returns falsy during creation of a resource's first secret revision; CustomValidationException carries the entity errors (HTTP 422-style validation response). Note the errors are read from the post-save (possibly replaced) entity, which can mask the real errors.
Solutions
- Capture $errors = $this->SecretRevisions->getErrors() before save and log them to see which field failed
- Ensure the associated Resource/Secret entities are persisted and have valid IDs before creating the revision
- Run pending migrations so the secret_revisions table exists with correct constraints
- Verify the payload passed into the revision (data, secrets association) satisfies the table's validation rules
Example fix
// before
$secretRevision = $this->SecretRevisions->save($secretRevision);
if (!$secretRevision) {
throw new CustomValidationException(__('Could not save secret revision'), $secretRevision->getErrors());
}
// after
$errors = $secretRevision->getErrors();
$secretRevision = $this->SecretRevisions->save($secretRevision);
if (!$secretRevision) {
throw new CustomValidationException(__('Could not save secret revision'), $errors);
} Defensive patterns
Strategy: try-catch
Validate before calling
$errors = $secretRevision->getErrors();
if ($errors) { throw new CustomValidationException(__('Invalid secret revision'), $errors); }
if (!$resource->id || !$secret->id) { throw new \InvalidArgumentException('Resource and secret must be persisted first'); } Try / catch
try {
$revision = $service->createFirstRevision($uac, $resourceId, $secrets);
} catch (CustomValidationException $e) {
Log::error('Revision validation failed', ['errors' => $e->getErrors()]);
} Prevention
- Persist parent Resource/Secret entities before creating revisions
- Capture entity errors BEFORE save() so errors aren't lost
- Run migrations so secret_revisions constraints exist
- Log full validation errors for failed saves
When it happens
Trigger: Creating the first secret revision for a new resource where the SecretRevisions table rejects the entity — invalid foreign keys (resource_id/secret_id), missing required fields, association save (secrets) failure, or rules such as unique revision constraints failing.
Common situations: Resource or secret not persisted before the revision save (ordering bug); data violating SecretRevisions validation rules (empty data, bad timestamps); database constraint violations surfaced as validation errors; schema drift after missing migrations.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- " " is not a valid search filter.
- " " is not a valid search filter. It is not a UTF8 string.
- " " is not a valid search filter. It should be between 1…
- " " is not a valid user filter.
- " " is not a valid value for filter .
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/3d2c14b2a92ffbcd.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltCe/SecretRevisions/src/Service/CreateSecretRevisionsService.php:79
'accessibleFields' => [
'resource_id' => true,
'resource_type_id' => true,
'created_by' => true,
'modified_by' => true,
],
]);
$secretRevision->secrets = $resource->secrets;
// For performance, we explicitly set the fields of the secrets as non-accessible, so the data for example
// of the secret is not persisted again.
// The goal here is only to persist the secret_revision_id field
foreach ($secretRevision->secrets as $secret) {
$secret->setAccess('*', false);
}
$secretRevision->setDirty('secrets');
/** @var \Passbolt\SecretRevisions\Model\Entity\SecretRevision $secretRevision */
$secretRevision = $this->SecretRevisions->save($secretRevision);
if (!$secretRevision) {
throw new CustomValidationException(__('Could not save secret revision'), $secretRevision->getErrors());
}
return $secretRevision;
}
/**
* - Soft delete the previous secret revision and secrets
* - creates a secret revision on resource update and associates it to:
* - the resource passed as parameter
* - the secrets associated to this resource
*
* @param \App\Model\Entity\Resource $resource the resource being saved
* @return \Passbolt\SecretRevisions\Model\Entity\SecretRevision
*/
public function createNewRevision(Resource $resource): ?SecretRevision
{
if (empty($resource->secrets)) {
return null;View on GitHub (pinned to 31c1bbc10f)