As suggested on GitHub, it was a problem with my local webserver configuration. I'm using a custom docker image and nginx proxy on local. I was able to fix it by adding the header in nginx.conf:
add_header X-Inertia "true";
# Current Environment (Local docker)
"php": "8.1"
"laravel/nova": "4.35.6"
"laravel/framework": "10.45.28"
I have been racking my brains for days over this problem and could not fix it yet. I would be so appreciate if someone could help me!
After upgrading my application from Laravel 9 to 10 by following the Upgrade Guide, I’ve encountered an issue with Laravel Nova’s UI. When I click on any sub-navigation item, I always receive the following error in a modal:
"All Inertia requests must receive a valid Inertia response, however a plain JSON response was received."
It appears that Nova is returning its usual JSON payload (containing configuration and menu data) while Inertia expects a proper Inertia response. I suspect this might be due to middleware interference or a misconfiguration with CORS. The subpages (like /resources/products or /my-custom-tool) can still be accessed by entering the URL directly.
CORS CONFIGURATION
Following a recommendation in StackOverflow, I added 'exposed_headers' => ['x-inertia'] to my config/cors.php. However, the Access-Control-Expose-Headers: x-inertia header is not showing up in my network responses. Maybe Nova is overriding it?
CORS MIDDLEWARE
Replaced Laravel 10 built-in CORS with the Fruitcake package fruitcake/laravel-cors
AUTHENTICATION
I also had to fix user authentication. At first it was using adldap. I tried to migrate to LdapRecord. Later I tried to use Auth0 instead, which also causes a lot of problems because of some breaking changes (Auth0 Thread, Nova 4 + Auth0). So I ended up by using simple session authentication, see auth.php below to get Login work again.
DEPENDENCIES UPDATES
php: "8.*" → "^8.1"
doctrine/dbal: "^2.8" → "^3.0"
laravel/framework: "9.*" → "10.*"
laravel/nova: "4.25.1" → "^4.35"
fruitcake/laravel-cors: "^2.0" → (removed)
spatie/laravel-permission: "5.*" → "^6.0"
auth0/auth0-php: "8.3.1" → "^8.10"
auth0/login: "7.1" → "^7.8"
itsmejoshua/novaspatiepermissions: "^1.0" → (removed)
kiritokatklian/nova-permission: (not present) → "*"
# ...
CMDs
Deleted /vendor and node_modules and executed:
composer update
npm i && npm run dev
php artisan route:clear && php artisan config:clear && php artisan cache:clear
php artisan optimize:clear
php artisan nova:publish
Here are some classes that could be involved:
/config/auth.php
// ...
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
]
/config/cors.php
return [
'paths' => ['*'],
'allowed_methods' => ['*'],
'allowed_origins' => ['*', 'http://localhost:3000', env('APP_URL')],
'allowed_origins_patterns' => [],
'allowed_headers' => ['*','content-type,x-inertia,x-inertia-version,x-requested-with'],
'exposed_headers' => ['x-inertia'],
'max_age' => 0,
'supports_credentials' => true,
];
/config/nova.php
// ...
'middleware' => [
'web',
HandleInertiaRequests::class,
DispatchServingNovaEvent::class,
BootTools::class,
\Vyuldashev\NovaPermission\ForgetCachedPermissions::class,
],
app/Http/Kernal.php
// ...
protected $middleware = [
\Laravel\Nova\Http\Middleware\HandleInertiaRequests::class,
\Illuminate\Http\Middleware\HandleCors::class,
\App\Http\Middleware\TrustProxies::class,
\App\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
];
/package.json
// ...
"devDependencies": {
"axios": "^0.27.2",
"cross-env": "^7.0.3",
"laravel-mix": "^6.0.49",
"lodash": "^4.17.13",
"postcss": "^8.3.11",
"resolve-url-loader": "^5.0.0",
"sass": "^1.54.9",
"sass-loader": "^12.6.0",
"vue": "^3.2.39",
"vue-loader": "^16.8.3",
"vue-template-compiler": "^2.6.11",
"vuex": "^4.0.2",
....
},
/Providers/NovaServiceProvider.php
// ...
public function boot()
{
parent::boot();
Nova::withBreadcrumbs();
// Global variables for custom tools
Nova::serving(function (ServingNova $event) { // ... }
// Main navigation - side menu
Nova::mainMenu(function (Request $request) {
return [
MenuSection::make(__('system.inventory_title'), [
MenuGroup::make(__('system.inventory_material'), [
MenuItem::link(__('inventory_product.title.plural'), '/resources/products'),
MenuItem::link(__('inventory_article.title.plural'), '/resources/articles'),
])->collapsable(),
])->icon('archive')->collapsable(),
// ...
MenuSection::make('System', [
// This is the only item that works now
MenuItem::link('API', '/api/documentation')->canSee(function (NovaRequest $request) {
return $request->user()->hasRole(['host', 'super-admin']);
}),
// ...
])->canSee(function (NovaRequest $request) {
return $request->user()->hasRole('super-admin');
}),
])->icon('cog')->collapsable()->collapsedByDefault(),
// ...
// ...
]
}
protected function routes()
{
Nova::routes()->withAuthenticationRoutes()->withPasswordResetRoutes()->register();
}
Maybe it's some problem in the official Laravel\Nova\Http\Middleware\HandleInertiaRequests class?
namespace Laravel\Nova\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Config;
use Inertia\Middleware;
use Laravel\Nova\Http\Resources\UserResource;
use Laravel\Nova\Nova;
class HandleInertiaRequests extends Middleware
{
/**
* The root template that's loaded on the first page visit.
*
* @see https://inertiajs.com/server-side-setup#root-template
*
* @var string
*/
protected $rootView = 'nova::layout';
/**
* Determines the current asset version.
*
* @see https://inertiajs.com/asset-versioning
*
* @param \Illuminate\Http\Request $request
* @return string|null
*/
public function version(Request $request)
{
return sprintf('%s:%s', $this->rootView, parent::version($request));
}
/**
* Defines the props that are shared by default.
*
* @see https://inertiajs.com/shared-data
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function share(Request $request)
{
return array_merge(parent::share($request), [
'novaConfig' => function () use ($request) {
return Nova::jsonVariables($request);
},
'currentUser' => function () use ($request) {
return with(Nova::user($request), function ($user) use ($request) {
return ! is_null($user) ? UserResource::make($user)->toArray($request) : null;
});
},
'validLicense' => function () use ($request) {
return with(Nova::user($request), function ($user) {
return ! is_null($user) ? Nova::checkLicenseValidity() : Cache::get('nova_valid_license_key');
});
},
]);
}
/**
* Handle the incoming request.
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function handle(Request $request, Closure $next)
{
Config::set('inertia.ssr.enabled', false);
return parent::handle($request, $next);
I’m at a loss. There are any additional configuration steps or middleware adjustments required to ensure Nova’s JSON responses aren’t being misinterpreted by Inertia? Any other troubleshooting steps or patches that might resolve this conflict?
Thank you for your assistance.
Best regards, Chris
As suggested on GitHub, it was a problem with my local webserver configuration. I'm using a custom docker image and nginx proxy on local. I was able to fix it by adding the header in nginx.conf:
add_header X-Inertia "true";
Please or to participate in this conversation.