{"record":{"id":"02ae35d97da37551","repo":"flarum/framework","slug":"validationexception-messages-from-validator","errorCode":null,"errorMessage":"ValidationException (messages from validator)","messagePattern":"ValidationException \\(messages from validator\\)","errorType":"validation","errorClass":"ValidationException","httpStatus":null,"severity":"warning","filePath":"framework/core/src/Foundation/AbstractValidator.php","lineNumber":53,"sourceCode":"    ) {\n    }\n\n    public function addConfiguration(callable $callable): void\n    {\n        $this->configuration[] = $callable;\n    }\n\n    /**\n     * Throw an exception if a model is not valid.\n     *\n     * @throws ValidationException\n     */\n    public function assertValid(array $attributes): void\n    {\n        $validator = $this->makeValidator($attributes);\n\n        if ($validator->fails()) {\n            throw new ValidationException($validator);\n        }\n    }\n\n    /**\n     * Whether to validate missing keys or to only validate provided data keys.\n     */\n    public function validateMissingKeys(bool $validateMissingKeys = true): static\n    {\n        $this->validateMissingKeys = $validateMissingKeys;\n\n        return $this;\n    }\n\n    public function prepare(array $attributes): static\n    {\n        $this->laravelValidator ??= $this->makeValidator($attributes);\n\n        return $this;","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/flarum/framework/blob/4b939f685389bfe8a380e9e28ddf305a1c66950c/framework/core/src/Foundation/AbstractValidator.php#L35-L71","documentation":"AbstractValidator::assertValid builds a Laravel validator from the subclass's rules via makeValidator and throws ValidationException carrying the validator whenever any rule fails. This is Flarum's central validation mechanism for user input (usernames, emails, tags, etc.), so the message set mirrors Laravel's validation messages.","triggerScenarios":"Any Flarum validator subclass's assertValid(array $attributes) receiving attributes that break configured rules — e.g. registering a username that's already taken, invalid email format, missing required fields, or attributes exceeding max lengths.","commonSituations":"API clients (POST /api/users, tag creation, profile edits) submitting payloads violating rules; extensions adding rules that existing stored data no longer satisfies; locale files missing so messages render as keys.","solutions":["Catch ValidationException and inspect getErrors()/errors() for the per-attribute messages, then correct the payload and retry.","Pre-validate attributes client-side against the same rules (required fields, email format, length limits) before calling the endpoint.","Check your validator subclass rules — overly strict rules (e.g. unique constraints with soft-deleted rows) may need adjustment."],"exampleFix":"// before: assuming success\n$user = $this->users->create($data);\n\n// after\ncatch (ValidationException $e) {\n    $errors = $e->getErrors()->toArray();\n    return response()->json(['errors' => $errors], 422);\n}","handlingStrategy":"try-catch","validationCode":"// mirror required fields before calling assertValid\n$missing = array_filter($rules, fn($r, $k) => str_contains($r, 'required') && !isset($attributes[$k]), ARRAY_FILTER_USE_BOTH);\nif ($missing) { throw new InvalidArgumentException('Missing: ' . implode(',', array_keys($missing))); }","typeGuard":null,"tryCatchPattern":"try {\n    $validator->assertValid($attributes);\n} catch (ValidationException $e) {\n    foreach ($e->errors()->all() as $message) { /* surface to user */ }\n}","preventionTips":["Always wrap assertValid in try-catch and return 422 with the error bag.","Validate payloads client-side against the same rules shown in the validator subclass.","Ensure translation files include validation message keys to avoid raw key output.","Review custom rules after upgrading Flarum or extensions."],"tags":["flarum","validation","laravel-validator","input"],"backgroundTag":"schema-validation-failed","analyzedSha":"4b939f685389bfe8a380e9e28ddf305a1c66950c","analyzedAt":"2026-09-15T18:09:20.879Z","contentChangedAt":"2026-09-15T18:09:20.879Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}