{"record":{"id":"fead7aaa98a489f0","repo":"flarum/framework","slug":"str-replace-attribute-users-this-translator-trans-validation","errorCode":null,"errorMessage":"str_replace(':attribute', 'users', $this->translator->trans('validation.required'))","messagePattern":"str_replace\\(':attribute', 'users', \\$this->translator->trans\\('validation\\.required'\\)\\)","errorType":"validation","errorClass":"ValidationException","httpStatus":422,"severity":"error","filePath":"extensions/messages/src/Api/Resource/DialogMessageResource.php","lineNumber":239,"sourceCode":"    /**\n     * @inheritDoc\n     */\n    public function creating(object $model, OriginalContext $context): ?object\n    {\n        $model->user_id = $context->getActor()->id;\n        $data = $context->body()['data'] ?? [];\n\n        $this->events->dispatch(\n            new DialogMessage\\Event\\Creating($model, $data)\n        );\n\n        if (! $model->dialog_id) {\n            $context->getActor()->assertCan('sendAnyMessage');\n\n            $users = array_filter(Arr::pluck($data['attributes']['users'] ?? [], 'id'), fn (mixed $id) => $id && $id != $model->user_id);\n\n            if (empty($users)) {\n                throw new ValidationException([\n                    'users' => str_replace(':attribute', 'users', $this->translator->trans('validation.required')),\n                ]);\n            }\n\n            $dialog = Dialog::for($model, $users);\n\n            $model->dialog()->associate($dialog);\n\n            $users[] = $model->user_id;\n\n            $dialog->users()->syncWithPivotValues(array_unique($users), [\n                'joined_at' => Carbon::now(),\n            ]);\n        }\n\n        return parent::creating($model, $context);\n    }\n","sourceCodeStart":221,"sourceCodeEnd":257,"githubUrl":"https://github.com/flarum/framework/blob/4b939f685389bfe8a380e9e28ddf305a1c66950c/extensions/messages/src/Api/Resource/DialogMessageResource.php#L221-L257","documentation":"When creating a dialog message without dialog_id, the resource checks the 'users' attribute for valid recipient ids (excluding the actor); if the resulting list is empty it throws a ValidationException on the 'users' field with the translated 'required' message. The odd message string shown is the raw translation call that generates the text.","triggerScenarios":"POST /api/dialog-messages without dialog_id and with attributes.users missing, empty, containing only null/blank ids, or containing only the sender's own id.","commonSituations":"Frontend not collecting recipients before send; user attempts to message only themselves; stale UI state after recipients were removed.","solutions":["Include attributes.users with at least one valid user id other than the sender.","Provide dialog_id to send into an existing dialog instead of creating a new one.","Ensure ids in the users array are integers/strings of existing users and not empty values.","Verify the frontend sends the recipients under data.attributes.users."],"exampleFix":"// before\n{ \"attributes\": { \"content\": \"hi\", \"users\": [] } }\n// after\n{ \"attributes\": { \"content\": \"hi\", \"users\": [{ \"id\": 7 }] } }","handlingStrategy":"validation","validationCode":"const users = (attrs.users ?? []).map(u => u.id).filter(id => id && id !== currentUserId); if (!attrs.dialog_id && users.length === 0) { /* require recipients before submit */ }","typeGuard":null,"tryCatchPattern":"try { await store.createRecord('dialog-messages', payload).save(); } catch (e) { if (e.errors?.users) show('Select at least one recipient'); }","preventionTips":["Require recipient selection in the UI when no dialog_id","Filter out the sender and empty ids client-side","Prefer dialog_id for existing conversations"],"tags":["validation","required-field","api"],"backgroundTag":"empty-required-field","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"}