passbolt/passbolt_api · error · ValidationException
Could not validate resource data.
Error message
Could not validate resource data.
What it means
ResourcesUpdateService throws this ValidationException when the entity built from the request fails Passbolt's resource model validation rules. It is raised in handleValidationErrors (src/Service/Resources/ResourcesUpdateService.php:251) whenever $resource->getErrors() is non-empty after building the resource, wrapping the entity so the API response includes per-field validation details.
Solutions
- Inspect the `errors` body of the 400 response; it maps each invalid field to its validation rule message.
- Fix the offending field client-side (trim/shorten name, correct URI, provide required fields).
- Check the Resources table validation rules (src/Model/Table/ResourcesTable.php) for the exact constraint triggered.
- If rules changed after a Passbolt upgrade, update the client payload to the new schema.
- Run the update again once the payload conforms.
Example fix
// before
PATCH payload: {"name": ""}
// -> 400 Could not validate resource data (name required)
// after
PATCH payload: {"name": "Q1 Planning"} Defensive patterns
Strategy: validation
Validate before calling
const RES_NAME_MAX = 255;
function validResourcePayload(payload) {
const errors = {};
if (!payload.name || !payload.name.trim()) errors.name = 'Name is required';
if (payload.name && payload.name.length > RES_NAME_MAX) errors.name = 'Name too long';
if (payload.uri && !/^([a-z][a-z0-9+.-]*):\/\//i.test(payload.uri)) errors.uri = 'Invalid URI scheme';
return Object.keys(errors).length ? errors : null;
}
// call before PUT /resources/{id}; abort if it returns errors Type guard
function isResourceDto(v) {
return typeof v === 'object' && v !== null && typeof v.name === 'string'
&& (v.uri === undefined || typeof v.uri === 'string');
} Try / catch
try {
await api.updateResource(id, payload);
} catch (e) {
if (e.status === 400 && e.body?.errors) {
// surface e.body.errors per-field to the user
} else throw e;
} Prevention
- Always read and surface the per-field `errors` map from 400 responses
- Enforce the same field limits client-side (name length, URI format)
- Keep client resource schema in sync after Passbolt upgrades
- Trim/normalize input before sending
When it happens
Trigger: PUT /resources/{id} with payload that violates resource rules: name/description constraints, expired metadata/key fields, invalid URI format, or schema violations on the resource entity during updateResource.
Common situations: Clients sending a name exceeding the DB column length, missing required fields when partial-update expectations are wrong, invalid resource URI (e.g. 'http://' scheme not allowed), or stale clients posting deprecated metadata fields after a schema migration.
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
- Could not validate the password policies settings.
- The resource metadata key data could not be updated.
- The role could not be saved.
- The user identifier should be a valid UUID or "me".
- " " is not a valid search filter.
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/4f2091f54f2122fb.
Report an issue: GitHub.
Appendix: source
Thrown at src/Service/Resources/ResourcesUpdateService.php:251
'secrets' => true,
]);
return $this->Resources->patchEntity($resource, $data, $options);
}
/**
* Handle resource validation errors.
*
* @param \App\Model\Entity\Resource $resource entity
* @return void
* @throws \App\Error\Exception\ValidationException
* @throws \Cake\Http\Exception\NotFoundException
*/
protected function handleValidationErrors(Resource $resource): void
{
$errors = $resource->getErrors();
if (!empty($errors)) {
throw new ValidationException(__('Could not validate resource data.'), $resource, $this->Resources);
}
}
/**
* Update the secrets.
*
* @param \App\Utility\UserAccessControl $uac The operator
* @param \App\Model\Entity\Resource $resource The target resource
* @param array $data The list of secrets to update
* @return array
* @throws \Exception If an unexpected error occurred
*/
private function decorateSecretsData(UserAccessControl $uac, Resource $resource, array $data): array
{
$data = Hash::insert($data, '{n}.modified_by', $uac->getId());
$data = Hash::insert($data, '{n}.created_by', $uac->getId());
return $data;View on GitHub (pinned to 31c1bbc10f)