Learn · Troubleshooting

Troubleshooting Web Forms uploads

Upload failures are usually one of a dozen specific causes, and the error message rarely names the right one. Find the symptom, get the cause.

HTTP 404.13 — "Request filtering module is configured to deny a request that exceeds the request content length"

IIS rejected the request before ASP.NET ever ran. Raise maxAllowedContentLength under requestFiltering. Note it is expressed in bytes, while the ASP.NET maxRequestLength beside it is in kilobytes — raising one and not the other is the most common reason a limit increase appears to do nothing. See large file uploads for both settings together.

"Maximum request length exceeded" (HttpException)

The ASP.NET side of the same limit: httpRuntime maxRequestLength, in kilobytes, default 4096 (4 MB). The real fix for anything genuinely large is chunking, so no single request approaches the limit at all.

Uploads 404 or 500 while the page itself loads fine

The upload handler is not reachable. Check that the HTTP handler is registered in Web.config, that the path matches what the client posts to, and that no URL rewrite rule is swallowing it.

<system.webServer>
  <validation validateIntegratedModeConfiguration="false" />
  <handlers>
    <remove name="AjaxUploader" />
    <add name="AjaxUploader" verb="*" path="ajaxupload.axd"
         type="AjaxUploader.AjaxUploaderHandler, AjaxUploader"
         preCondition="integratedMode" />
  </handlers>
</system.webServer>

If the site runs in a virtual directory, make sure the client is using an application-relative URL (ResolveUrl("~/ajaxupload.axd/upload")) rather than a hard-coded /ajaxupload.axd, which resolves to the wrong application.

Single uploads work, chunked uploads fail

Almost always a protocol mismatch between what the client sends and what the endpoint parses. The chunk endpoint receives the chunk bytes as the raw request body with metadata in headers; a handler written to parse a multipart form will find nothing and fail on every chunk while ordinary uploads keep working. Confirm the chunk, chunk-complete and status URLs are all configured, and test with a file genuinely larger than the chunk size — a smaller file silently takes the single-upload path and proves nothing.

Progress reaches 100%, then the upload fails

The bytes arrived; something after that rejected them. In order of likelihood: server-side validation (extension, size or MIME) firing at completion, an exception in your FileUploaded handler, a permissions failure writing to the destination folder, or a disk that is full. Look at the server log, not the browser — the client only knows the request failed.

Upload dies at a consistent elapsed time

A timeout, not a size limit. Suspects, in order: ASP.NET executionTimeout (default 110 seconds), the IIS connection timeout, and any reverse proxy or load balancer in front (nginx proxy_read_timeout, ALB idle timeout). If it always dies at exactly 60 or 120 seconds, something in that list is set to exactly that.

The page posts back and the upload is lost

A Web Forms specific trap. The uploader transfers files out of band, then your postback re-renders the page; if the control's state is not preserved, the queue appears to reset. Keep ViewState enabled for the uploader, do not recreate the control in code after Page_Load, and read uploaded files from the server-side event or the control's file collection rather than expecting them in Request.Files.

Files upload but are not where you expect

By design, files land in a temporary location first and are moved by your code. If nothing moves them they are eventually swept. Handle FileUploaded and copy the file to its permanent home — and give it a name you generated, not the client's:

protected void Uploader1_FileUploaded(object sender, FileUploadedEventArgs e)
{
    var targetFolder = Server.MapPath("~/App_Data/uploads");
    Directory.CreateDirectory(targetFolder);

    var safeName = Guid.NewGuid().ToString("N") +
                   Path.GetExtension(e.FileName ?? string.Empty);

    new UploadService().CopyFile(e.FileGuid, Path.Combine(targetFolder, safeName));
}

"Access denied" writing the file

The application pool identity needs write permission on the temp folder and the destination. Grant it to the pool identity (IIS AppPool\YourPoolName) rather than to a broad group, and remember that a UNC destination needs the pool running as an account the file server recognises.

Works locally, fails on the server

The differences that matter: IIS Express does not apply request filtering the same way full IIS does; the deployed site may run in a virtual directory that breaks absolute URLs; HTTPS is required for encryption and service-worker features because they need a secure context; and a proxy in front adds timeouts and body-size limits of its own. Check request filtering, the resolved handler URL, and the proxy's body limit in that order.

Antiforgery / CSRF rejections

If antiforgery is enabled, every upload request must carry the token — including chunk requests, which do not go through the normal form post. Make sure the token is supplied on each request, and that the session is still alive: an expired session invalidates the token, so a long upload started before a session timeout will fail near the end.

Still stuck? Narrow it down like this

  1. Does a tiny file upload succeed? If not, the problem is wiring, not limits.
  2. Does a file just over the chunk size succeed? If not, the problem is the chunk path specifically.
  3. Watch the network panel: which request fails, and with what status? A 404.13 is IIS, a 500 is your code, no response at all is a timeout.
  4. Read the server log for that request id. The browser's error message is downstream of the real one.