InertiaJS useForm Returns 422 but form.errors Stays Empty
An InertiaJS form submission returns HTTP 422, but form.errors stays empty and validation messages never render. Use this diagnostic guide to isolate the backend, package version, or error-handling cause.
30 Apr 2026, 05:54 UTC

The problem and what to check first
You submit an InertiaJS form, the Network tab shows HTTP 422, yet form.errors is empty and no validation messages appear. The form may look like it succeeded, or it may hang. This often appears after a deploy or dependency change.
The useful takeaway is that a 422 status alone does not populate Inertia's error bag. Inertia's error bag is the client-side object that holds validation errors returned by the server. For it to work, the response body must include a JSON errors key, the client and server Inertia packages must share a major version, and your onFinish handler must read errors instead of discarding it.
Recognizable condition
- DevTools Network tab shows the submission request with status 422.
- The response body contains validation errors, but
form.errorsremains an empty object. - No inline validation messages render under the form fields.
- The behavior started after a deploy, package upgrade, or middleware change.
Cause and diagnostic table
| Observed symptom | Likely cause | Where to look |
|---|---|---|
422 response, but no JSON errors key in the body | Backend omits validation errors or returns a 200 with errors nested inside data | Network response body |
422 with errors, but form.errors is empty | Client and server Inertia packages are on different major versions | package.json and composer.json |
422 with errors, versions match, but form.errors is empty | onFinish swallows the response or never reads errors | Frontend form component |
Ordered checks
1. Confirm the network response
Open Chrome or Firefox DevTools, go to the Network tab, submit the form, and select the submission request.
- Expected status: 422 Unprocessable Entity.
- Expected body: a JSON object with an
errorskey, for example{ "errors": { "email": ["The email is already taken."] } }. - Risk: None. This is a read-only inspection.
2. Confirm the backend returns validation errors
Inertia's Laravel middleware serializes validation failures into the shared error bag only when the server throws a validation exception or returns errors with a 422 response. If your controller returns a successful response and puts errors inside data, Inertia will not populate form.errors automatically.
Check the controller or form request. It should use Laravel validation, which throws Illuminate\Validation\ValidationException on failure:
use Illuminate\Validation\ValidationException;
throw ValidationException::withMessages([
'email' => ['The email address is already taken.'],
]);
Alternatively, $request->validate([...]) throws the same exception automatically.
3. Check client and server Inertia versions
Run these read-only commands from the project root:
# Client package version
npm list @inertiajs/vue3 # or @inertiajs/react
# Server package version
composer show inertiajs/inertia-laravel
Required permissions: read access to package.json, composer.json, and lock files. No sudo or deploy permissions are needed for inspection.
Both packages should target the same Inertia major version, typically v1. Mixing Inertia v0 on the client with v1 on the server, or vice versa, can silently change the error payload shape and drop validation errors.
4. Inspect onFinish
Open the Vue or React component that owns the form. The useForm helper accepts an onFinish callback that runs after the request completes, whether it succeeds or fails.
import { useForm } from '@inertiajs/vue3'
const form = useForm({
email: '',
})
async function submit() {
await form.post('/users', {
onFinish: () => {
// Read errors here. This runs after a 422 too.
console.log(form.errors)
},
})
}
Do not wrap form.post in a generic try/catch that discards the response. Inertia handles the 422 and populates form.errors; swallowing the response can hide the error bag from your template.
Fixes tied to findings
Fix 1: Backend omits errors
If the network response lacks a JSON errors key, update the controller to throw a validation exception or return errors with status 422 so Inertia can populate the error bag.
// Laravel controller example
$validated = $request->validate([
'email' => 'required|email|unique:users',
]);
Rollback: revert the controller edit with version control if other clients depend on the previous response shape.
Fix 2: Align package versions
If the client and server major versions differ, update them to match, typically v1.
# Example only; adjust to your locked versions
npm install @inertiajs/vue3@latest
composer require inertiajs/inertia-laravel:^1.0
Risk: dependency changes can affect page props, redirects, and error handling across the app. Test navigation and other forms after upgrading.
Rollback: restore previous versions from package-lock.json or composer.lock and reinstall.
Fix 3: Read errors in onFinish
If onFinish is absent or discards the result, add logic that reads form.errors and renders field messages:
{Object.entries(form.errors).map(([field, messages]) => (
{messages.join(', ')}
))}
Rollback: revert the component edit if the new rendering breaks existing layout.
Escalation criteria
Escalate when all of the following are true:
- Network shows 422 with a correct JSON
errorsobject. - Client and server Inertia packages share the same major version.
onFinishreceives the error and logsform.errors.form.errorsremains empty across browsers after clearing Inertia-related cache or session storage.
At that point the issue is likely custom middleware stripping the error bag or a framework bug, not a configuration mistake.
Limitations and verification
This guide covers InertiaJS with a Laravel backend. Other server adapters may serialize validation errors differently. It does not cover operating-system hibernation; InertiaJS is a web SPA framework, not a power state.
Verify the fix by submitting the form again and confirming:
- Network status is 422 on validation failure.
form.errorscontains field-keyed error arrays insideonFinish.- Validation messages render under the corresponding fields.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.