Troubleshooting

Common errors, their causes, and how to fix them.

Inertia.Render(...) does not compile

'Inertia' is a namespace. Call Render(...) unqualified. The namespace Inertia.Net shadows the class name outside the Inertia.Net namespace.

The global usings come from the package's buildTransitive props and need <ImplicitUsings>enable</ImplicitUsings>. Without implicit usings, or with InertiaNetImplicitUsings set to false, add using static Inertia.Net.Inertia;.

Generated code fails with 'Inertia' is a type

Inside a namespace that starts with Inertia.Net., the name Inertia binds to the Inertia.Net.Inertia class. Source generators that emit non-global:: names starting with Inertia then break. Do not put your app's code under an Inertia.Net.* namespace.

Vite manifest not found. Looked in: ...

Run npm run build, or start the dev server so the hot file exists in Development, or set o.Vite.ManifestPath / o.Vite.BuildDirectory. Check that Vite writes .vite/manifest.json (build.manifest: true, Vite 5 and later) to wwwroot/build, and that the build output is part of what you deploy.

Vite entry '...' was not found in the manifest

The @vite("...") argument must equal the manifest key, which is the path relative to the Vite root. The error lists the available entries.

Form submissions fail with 419

UseInertiaAntiforgery() rejected a request without a valid X-XSRF-TOKEN. Check that:

  • the page was loaded through the middleware (it sets the XSRF-TOKEN cookie);
  • the cookie reaches the browser (Secure on plain HTTP is dropped; see Deploying);
  • all instances share the Data Protection key ring;
  • UseAuthentication() runs before it.

A sign-in or sign-out changes the token: reload the page, or return Back() from OnRejected. Exempt webhooks and token-authenticated APIs with .DisableAntiforgery() or ShouldValidate.

The Inertia page component was not found

o.Pages.Directory is set and the component passed to Render(...) has no page file there. Names match exactly, as the client's page resolver does, even on case-insensitive file systems; the message suggests the closest page. Fix the name, or check Pages.Extensions when your pages use another extension. The check never runs outside Development.

A redirect to another site turns into a 409

That is ConvertExternalRedirects (on by default): an Inertia request cannot follow a redirect to another origin, so it gets 409 + X-Inertia-Location and the client does a full visit.

If it happens for your own host, the app is behind a proxy that does not forward the scheme (see Deploying), or use relative redirects. o.ConvertExternalRedirects = false disables the conversion.

The root view resolves outside the content root

RootView and WithRootView(...) take a path relative to the content root; absolute paths and .. are refused. Never derive them from request data.

The page keeps reloading, or a request loops with 409

A 409 means the asset version differs between the client and the server. A loop means it never converges: usually the version changes on every request (a VersionResolver that returns a new value each time, or a manifest regenerated by a file watcher), or different instances behind a load balancer serve different builds. Use a stable version string.

In Development the manifest hash changes after each vite build, which is expected once.

The dev server tags do not appear

The hot file is read only when ASPNETCORE_ENVIRONMENT=Development. Check that wwwroot/hot exists and contains http://localhost:5173, or set o.Vite.DevServerUrl. Remember base: '/' for the dev server in vite.config.

The root template was not found, or @inertia is missing

RootView is relative to the content root. Copy app.html to the output and publish directories (CopyToOutputDirectory, CopyToPublishDirectory). The template must contain @inertia.

Flash data or errors disappear

The state cookie is limited to about 4 KB by browsers. Flash less data, or use o.State.UseSession(). If the app runs on several instances, share Data Protection keys.

If the cookie is never sent back, check the cookie Secure flag on HTTP behind a proxy that does not forward X-Forwarded-Proto.

Validation errors do not show up (Minimal API)

Use .WithInertiaValidation() on the endpoint. Without it, the built-in AddValidation() filter returns a 400 problem details that the Inertia client cannot use. Make sure the model types are public.

Validation keys do not match my field names

Keys go through the JSON naming policy per segment (Address.Street becomes address.street). In MVC the policy is the one in the MVC JsonOptions. The page itself is written with the HTTP JsonOptions: keep both policies aligned.

InertiaProp values can only be serialized by Inertia.Net

An InertiaProp ended up somewhere Inertia.Net does not walk: a Flash(...) value, a read-only dictionary type that does not implement IDictionary, or a type with a custom converter.

Lists, typed dictionaries (Dictionary<TKey, TValue> with any key type), object members and IDictionary<string, object?> are walked. Put props in InertiaProps, or declare the member as InertiaProp (or object) on the typed page object.

Native AOT: JsonTypeInfo metadata was not provided

Add the type to your JsonSerializerContext and chain it with ConfigureHttpJsonOptions. Setting JsonSerializerIsReflectionEnabledByDefault=false in regular builds finds these early. See Native AOT.

SSR does not run and there is no error

SSR falls back to client rendering on any failure. Look for the warnings Inertia SSR failed (...) and Inertia SSR skipped (...). The first includes the server's hint.

Check o.Ssr.Mode, Urls, that the Node server is running (GET /health; with UseNodeProcess() look for Inertia.Net.Ssr log lines), that BundlePath points at the built file, that the path is not in ExcludePaths, and that the page is under MaxPageBytes.

Set Mode = SsrMode.Required in Development to surface the failure.

SSR skipped (circuit-open) or (overloaded)

  • circuit-open: the server failed CircuitBreaker.FailureThreshold times in a row and is skipped for BreakDuration; the earlier Inertia SSR failed warnings say why.
  • overloaded: more renders arrived than Concurrency.MaxActive plus MaxQueued, or one waited longer than QueueTimeout. Add servers or instances, or raise the limits if the server has headroom.

Several managed instances never become healthy

Every instance must listen on its own port: the SSR entry has to read process.env.INERTIA_SSR_PORT. A bundle built only by @inertiajs/vite listens on its baked-in port.

The SSR output is not hydrated

Use the hydrating client entry shown in Server-side rendering and build both bundles from the same sources. The SSR body is marked data-server-rendered="true".

Does it work behind a path base?

Yes. The page url keeps the path base, the Vite URLs include it, and Back() works.

Can I use Newtonsoft.Json?

No. Props use System.Text.Json with the HTTP JSON options.

Can I mix Razor Pages or views with Inertia pages?

Yes. Inertia handles only the endpoints that return Render(...). The middleware leaves other responses alone, apart from Vary: X-Inertia.