{"record":{"id":"4f2091f54f2122fb","repo":"passbolt/passbolt_api","slug":"could-not-validate-resource-data-resourcesupdateservice","errorCode":null,"errorMessage":"Could not validate resource data.","messagePattern":"Could not validate resource data\\.","errorType":"validation","errorClass":"ValidationException","httpStatus":400,"severity":"error","filePath":"src/Service/Resources/ResourcesUpdateService.php","lineNumber":251,"sourceCode":"            'secrets' => true,\n        ]);\n\n        return $this->Resources->patchEntity($resource, $data, $options);\n    }\n\n    /**\n     * Handle resource validation errors.\n     *\n     * @param \\App\\Model\\Entity\\Resource $resource entity\n     * @return void\n     * @throws \\App\\Error\\Exception\\ValidationException\n     * @throws \\Cake\\Http\\Exception\\NotFoundException\n     */\n    protected function handleValidationErrors(Resource $resource): void\n    {\n        $errors = $resource->getErrors();\n        if (!empty($errors)) {\n            throw new ValidationException(__('Could not validate resource data.'), $resource, $this->Resources);\n        }\n    }\n\n    /**\n     * Update the secrets.\n     *\n     * @param \\App\\Utility\\UserAccessControl $uac The operator\n     * @param \\App\\Model\\Entity\\Resource $resource The target resource\n     * @param array $data The list of secrets to update\n     * @return array\n     * @throws \\Exception If an unexpected error occurred\n     */\n    private function decorateSecretsData(UserAccessControl $uac, Resource $resource, array $data): array\n    {\n        $data = Hash::insert($data, '{n}.modified_by', $uac->getId());\n        $data = Hash::insert($data, '{n}.created_by', $uac->getId());\n\n        return $data;","sourceCodeStart":233,"sourceCodeEnd":269,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/src/Service/Resources/ResourcesUpdateService.php#L233-L269","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nPATCH payload: {\"name\": \"\"}\n// -> 400 Could not validate resource data (name required)\n// after\nPATCH payload: {\"name\": \"Q1 Planning\"}","handlingStrategy":"validation","validationCode":"const RES_NAME_MAX = 255;\nfunction validResourcePayload(payload) {\n  const errors = {};\n  if (!payload.name || !payload.name.trim()) errors.name = 'Name is required';\n  if (payload.name && payload.name.length > RES_NAME_MAX) errors.name = 'Name too long';\n  if (payload.uri && !/^([a-z][a-z0-9+.-]*):\\/\\//i.test(payload.uri)) errors.uri = 'Invalid URI scheme';\n  return Object.keys(errors).length ? errors : null;\n}\n// call before PUT /resources/{id}; abort if it returns errors","typeGuard":"function isResourceDto(v) {\n  return typeof v === 'object' && v !== null && typeof v.name === 'string'\n    && (v.uri === undefined || typeof v.uri === 'string');\n}","tryCatchPattern":"try {\n  await api.updateResource(id, payload);\n} catch (e) {\n  if (e.status === 400 && e.body?.errors) {\n    // surface e.body.errors per-field to the user\n  } else throw e;\n}","preventionTips":["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"],"tags":["validation","resources","cakephp","passbolt"],"backgroundTag":"schema-validation-failed","analyzedSha":"31c1bbc10f32808a607fa9bd81891e898779c0bc","analyzedAt":"2026-09-17T00:04:38.960Z","contentChangedAt":"2026-09-17T00:04:38.960Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}