dotnet/aspnetcore · error · AntiforgeryValidationException

Unable to read the antiforgery request token from the…

Error message

Unable to read the antiforgery request token from the posted form.

What it means

Thrown by DefaultAntiforgeryTokenStore when ReadFormAsync raises InvalidDataException while reading the posted form. The store wraps it in AntiforgeryValidationException so the pipeline treats it as a normal antiforgery failure (typically a 400) rather than a server error. Malformed form content is the root cause.

Solutions

  1. Inspect the raw request (boundary, Content-Type, body) and fix the malformed multipart construction on the client.
  2. Raise FormOptions.MultipartBodyLengthLimit / Kestrel limits if the upload legitimately exceeds defaults and the error is masking a size rejection.
  3. Ensure any proxy between client and server forwards the full body and Content-Type unchanged.
  4. Reproduce with a known-good form (e.g. a real <form> submit) to confirm the client code is the source of the malformed body.

Example fix

// before: hand-built multipart with wrong boundary
const body = '--boundary\r\nfield=value';

// after: use FormData, which builds a valid multipart body
const fd = new FormData();
fd.append('field', 'value');
await fetch('/submit', { method:'POST', body: fd });
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate request body basics before reading form: ensure Content-Type is multipart/form-data and body length <= configured limit.

Try / catch

try { await httpContext.Request.ReadFormAsync(); }
catch (InvalidDataException ex) { /* treat as 400, log detail */ }

Prevention

When it happens

Trigger: A request whose multipart/form-data or URL-encoded body is malformed (bad boundary, oversized fields beyond limits, corrupt multipart, invalid characters) reaches GetRequestTokensAsync, and ReadFormAsync throws InvalidDataException.

Common situations: Client constructing multipart bodies by hand with an incorrect boundary; upload exceeding Kestrel/IIS form size limits; a truncated body from a network drop or a misbehaving proxy; encoded content that violates the form parser rules.

Related errors


AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11). Data as JSON: /api/errors/bc3725f461bda88f. Report an issue: GitHub.

Appendix: source

Thrown at src/Antiforgery/src/Internal/DefaultAntiforgeryTokenStore.cs:64

        {
            requestToken = httpContext.Request.Headers[_options.HeaderName];
        }

        // Fall back to reading form instead
        if (requestToken.Count == 0 && httpContext.Request.HasFormContentType && !_options.SuppressReadingTokenFromFormBody)
        {
            // Check the content-type before accessing the form collection to make sure
            // we report errors gracefully.
            IFormCollection form;
            try
            {
                form = await httpContext.Request.ReadFormAsync();
            }
            catch (InvalidDataException ex)
            {
                // ReadFormAsync can throw InvalidDataException if the form content is malformed.
                // Wrap it in an AntiforgeryValidationException and allow the caller to handle it as just another antiforgery failure.
                throw new AntiforgeryValidationException(Resources.AntiforgeryToken_UnableToReadRequest, ex);
            }
            catch (IOException ex)
            {
                // Reading the request body (which happens as part of ReadFromAsync) may throw an exception if a client disconnects.
                // Wrap it in an AntiforgeryValidationException and allow the caller to handle it as just another antiforgery failure.
                throw new AntiforgeryValidationException(Resources.AntiforgeryToken_UnableToReadRequest, ex);
            }

            requestToken = form[_options.FormFieldName];
        }

        return new AntiforgeryTokenSet(requestToken, cookieToken, _options.FormFieldName, _options.HeaderName);
    }

    public void SaveCookieToken(HttpContext httpContext, string token)
    {
        Debug.Assert(httpContext != null);
        Debug.Assert(token != null);

View on GitHub (pinned to 3600ca084e)