dotnet/aspnetcore · error · Error
Cannot perform enhanced form submission that changes the…
Error message
Cannot perform enhanced form submission that changes the URL (except via a redirection), because then back/forward would not work. Either remove this form's 'action' attribute, or change its method to 'get', or do not mark it as enhanced.
Old URL: ${location.href}
New URL: ${response.url} What it means
Enhanced navigation cannot support a non-GET form submission that lands on a different URL without a redirection, because the browser history entry would be un-recreatable: there is no way to reproduce a 'resubmit this POST?' prompt on back/forward. The check is intentionally delayed until after SSR completes (in case SSR emits a redirect signal), then throws if no redirect occurred. Reference: dotnet/aspnetcore#50945.
Solutions
- Remove the form's action attribute so it posts back to the current URL (Blazor-enhanced POST to the same URL is allowed).
- Change the form method to 'get'.
- Remove data-enhance / do not mark the form as enhanced.
- Implement a post/redirect/get: POST returns a 303 See Other to the destination so response.redirected is true.
Example fix
<!-- before --> <form method="post" action="/other-url" data-enhance="true"> <!-- after: post to the same URL --> <form method="post" data-enhance="true"> <!-- no action, posts to current page -->
Defensive patterns
Strategy: validation
Validate before calling
// Do not enhance POST forms whose action differs from the current URL unless they redirect
function shouldEnhancePost(form: HTMLFormElement): boolean {
const method = (form.getAttribute('method') || 'get').toLowerCase();
if (method !== 'post') return true;
const action = form.getAttribute('action');
if (!action) return true; // posts to current URL
const here = window.location.pathname + window.location.search;
return new URL(form.action, window.location.href).pathname + new URL(form.action, window.location.href).search === here;
}
if (!shouldEnhancePost(form)) form.removeAttribute('data-enhance'); Try / catch
try {
await enhancedNavSubmit(form);
} catch (e) {
if (/changes the URL/i.test((e as Error).message)) {
// fall back: full POST
form.removeAttribute('data-enhance');
(form as HTMLFormElement & { submit(): void }).submit();
} else throw e;
} Prevention
- Omit the action attribute on enhanced POST forms so they post to the current URL.
- Use GET for forms that should change the URL.
- Implement post/redirect/get (303) for cross-URL POSTs you still want enhanced.
- Only mark a form as enhanced when you control both its action and its response.
When it happens
Trigger: Thrown at line 362 via the isNonRedirectedPostToADifferentUrlMessage string after enhanced SSR completes, when the request was a non-GET (POST/PUT) to a different URL than the current page and the response was not a redirect that the browser followed.
Common situations: An enhanced form with an explicit action attribute pointing to a different URL than the current page, posting without a post/redirect/get pattern; action='/search' on a page at '/' with method=post and data-enhance.
Related errors
- Enhanced navigation does not support making a non-GET…
- Enhanced navigation does not support making a non-GET…
- No enhanced programmatic navigation handler has been…
- ' ' is flagged with SingleDelivery, but the selected…
- A public property ' ' on component type ' ' with a public…
AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11).
Data as JSON: /api/errors/c4cfeda28086916a.
Report an issue: GitHub.
Appendix: source
Thrown at src/Components/Web.JS/src/Services/NavigationEnhancement.ts:362
// has since started). So finally, recreate the native "scroll to hash" behavior.
const hashPosition = internalDestinationHref.indexOf('#');
if (hashPosition >= 0) {
const hash = internalDestinationHref.substring(hashPosition + 1);
const targetElem = document.getElementById(hash);
targetElem?.scrollIntoView();
}
performingEnhancedPageLoad = false;
navigationEnhancementCallbacks.enhancedNavigationCompleted();
// For non-GET requests, the destination has to be the same URL you're already on, or result in a redirection
// (post/redirect/get). You're not allowed to POST to a different URL without redirecting, because then back/forwards
// won't work - we can't recreate the "Resubmit form?" behavior.
// See https://github.com/dotnet/aspnetcore/issues/50945
// The reason we delay throwing until after SSR completes is that SSR might include a redirection signal. If we get
// here without navigating away, it's an error.
if (isNonRedirectedPostToADifferentUrlMessage) {
throw new Error(isNonRedirectedPostToADifferentUrlMessage);
}
}
}
async function getResponsePartsWithFraming(responsePromise: Promise<Response>, abortSignal: AbortSignal, onInitialDocument: (response: Response, initialDocumentText: string) => void, onStreamingElement: (streamingElementMarkup) => void) {
let response: Response;
try {
response = await responsePromise;
if (!response.body) { // Not sure how this can happen, but the TypeScript annotations suggest it can
onInitialDocument(response, '');
return;
}
const frameBoundary = response.headers.get('ssr-framing');
if (!frameBoundary) {
// Shouldn't happen, but perhaps some proxy stripped the headers. In that case we just won't respect streaming and willView on GitHub (pinned to 3600ca084e)