diff --git a/resources/js/Pages/Endpoints/Index.vue b/resources/js/Pages/Endpoints/Index.vue index 93e0f75..e4ecdb8 100644 --- a/resources/js/Pages/Endpoints/Index.vue +++ b/resources/js/Pages/Endpoints/Index.vue @@ -415,7 +415,19 @@ async function saveEndpoint() { showOneTimeSecret(response.data.plain_secret) } catch (error) { if (error.response?.data?.errors) { - form.setError(error.response.data.errors) + // Laravel's JSON validation-error response shapes each field + // as an array of messages. A normal Inertia form submission + // flattens these before they reach the client, but this is a + // raw axios call, so it must be flattened here too — otherwise + // form.setError() stores the array itself and InputError.vue + // (which expects a string) renders it as a JSON blob. + const errors = Object.fromEntries( + Object.entries(error.response.data.errors).map(([field, messages]) => [ + field, + Array.isArray(messages) ? messages[0] : messages, + ]) + ) + form.setError(errors) } else { alert('Failed to save endpoint. Please try again.') } diff --git a/tests/Feature/EndpointCreateValidationErrorFormatTest.php b/tests/Feature/EndpointCreateValidationErrorFormatTest.php new file mode 100644 index 0000000..03bc097 --- /dev/null +++ b/tests/Feature/EndpointCreateValidationErrorFormatTest.php @@ -0,0 +1,35 @@ +withPersonalTeam()->create(); + + $response = $this->actingAs($user)->postJson('/endpoints', [ + 'name' => '', + 'url' => 'not-a-url', + ]); + + $response->assertStatus(422); + $response->assertJsonValidationErrors(['name', 'url']); + $this->assertIsArray($response->json('errors.name')); + $this->assertIsArray($response->json('errors.url')); + } +}