{"record":{"id":"c049f8df39017a8c","repo":"passbolt/passbolt_api","slug":"400-could-not-validate-tags-data","errorCode":"400","errorMessage":"Could not validate tags data.","messagePattern":"Could not validate tags data\\.","errorType":"validation","errorClass":"CustomValidationException","httpStatus":400,"severity":"error","filePath":"plugins/PassboltEe/Tags/src/Model/Table/TagsTable.php","lineNumber":438,"sourceCode":"            try {\n                $collection[$i] = $this->buildEntityOrFail($dto);\n\n                // If not shared, add the user_id in the resources_tags join table\n                $resourceTagUserId = null;\n                if ($dto->isPersonal()) {\n                    $resourceTagUserId = $userId;\n                }\n                $collection[$i]['_joinData'] = $this->ResourcesTags->newEntity(\n                    ['user_id' => $resourceTagUserId],\n                    ['accessibleFields' => ['user_id' => true]]\n                );\n            } catch (CustomValidationException $e) {\n                $errors[$i] = $e->getErrors();\n            }\n        }\n\n        if (!empty($errors)) {\n            throw new CustomValidationException(__('Could not validate tags data.'), $errors);\n        }\n\n        return $collection;\n    }\n\n    /**\n     * @param \\Passbolt\\Tags\\Model\\Dto\\MetadataTagDto $dto DTO.\n     * @return \\Passbolt\\Tags\\Model\\Entity\\Tag\n     * @throws \\App\\Error\\Exception\\CustomValidationException When there are errors building entity object.\n     */\n    public function buildEntityOrFail(MetadataTagDto $dto): Tag\n    {\n        $tag = $dto->toArray();\n\n        if ($dto->isV5()) {\n            $data = [\n                'metadata' => $tag['metadata'],\n                'metadata_key_id' => $tag['metadata_key_id'],","sourceCodeStart":420,"sourceCodeEnd":456,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltEe/Tags/src/Model/Table/TagsTable.php#L420-L456","documentation":"TagsTable::buildEntitiesOrFail validates a batch of tag payloads and aggregates per-entity validation errors. When any entity in the collection fails CakePHP validation, it throws CustomValidationException with this message and the indexed error map. It is the batch-level guard so clients see all failing rows at once.","triggerScenarios":"POST/PUT to the tags endpoint with an array of tag payloads where at least one slug fails validation (empty slug, slug exceeding max length, invalid characters, or non-permitted fields).","commonSituations":"Client sends tags with empty strings, overly long slugs (e.g. >128 chars pasted from elsewhere), or mixed personal/shared ('#' prefix) tags with invalid formats; API consumers not trimming whitespace before submitting.","solutions":["Inspect the error map in the exception payload: keys are array indexes of the failing tags, values are the field validation errors.","Fix the offending slug(s) in the failing indexes (trim, shorten to allowed length, keep allowed charset).","Ensure shared tags start with '#' and personal tags do not.","Retry with only valid tag payloads."],"exampleFix":"// before\nPATCH tags: [{\"slug\":\"\"},{\"slug\":\"release#1\"}]\n// after\nPATCH tags: [{\"slug\":\"release-1\"}]","handlingStrategy":"validation","validationCode":"$errors = [];\nforeach ($tagPayloads as $i => $p) {\n    $slug = trim($p['slug'] ?? '');\n    if ($slug === '' || mb_strlen($slug) > 128) { $errors[$i] = ['slug' => 'invalid']; }\n}\nif ($errors) { throw new \\InvalidArgumentException(json_encode($errors)); }","typeGuard":"function isValidTagSlug(mixed $slug): bool {\n    return is_string($slug) && trim($slug) !== '' && mb_strlen(trim($slug)) <= 128;\n}","tryCatchPattern":"try {\n    $tags = $tagsTable->buildEntitiesOrFail($payloads);\n} catch (CustomValidationException $e) {\n    foreach ($e->getErrors() as $idx => $fieldErrors) {\n        $this->log(\"Tag at index $idx failed: \" . json_encode($fieldErrors));\n    }\n}","preventionTips":["Trim and length-check slugs before submitting","Keep '#' prefix only on shared tags","Validate with the same rules client-side","Strip unknown fields from payloads"],"tags":["validation","tags","cakephp"],"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"}