When 500 KB is not 500 KB

By Filewhisk Team Published

The same file is two different sizes depending on who is counting, and the gap is exactly wide enough to get your upload rejected.

A form says maximum 500 KB. Your file is 500 KB — your computer says so. The upload is rejected anyway. Nothing is broken, nobody made a mistake, and the file really is 500 KB. It is just that at least three different programs counted it, and at least two of them used a different kilobyte.

This is usually explained and left there: KB is 1,000 bytes, KiB is 1,024, some people mix them up. That is true and not very useful, because it does not tell you which one is on the other end of the form you are staring at. So we measured it — our own compressors, the defaults that ship with three widely used web frameworks, and our own interface, which turned out to be part of the problem.

The gap has a size, and it is not small

Two readings of the same limit:

Stated limitIf KB means 1,000If KB means 1,024Files caught in between
100 KB100,000 bytes102,400 bytes2,400 bytes wide
500 KB500,000 bytes512,000 bytes12,000 bytes wide
1 MB1,000,000 bytes1,048,576 bytes48,576 bytes wide
2 MB2,000,000 bytes2,097,152 bytes97,152 bytes wide

The last column is the trap. A 2 MB file is not rejected because it is wildly too big; it is rejected because it landed in a 97 KB window where one program thinks it fits and another does not. And the closer you compress to the stated number, the more likely you are to land exactly there. Compressing harder is the fix, which feels absurd when the tool already told you it hit the target.

What our compressors actually produce

We ran the same difficult source image — 13.5 MB, noisy, the kind that resists compression — through four target-size pages in a real browser and read the byte count of each downloaded file.

PageTarget you typeBytes producedUnder 1,000-based limit?Under 1,024-based limit?
compress-image-to-100kb100 KB79,141YesYes
compress-image-to-200kb200 KB189,136YesYes
compress-image-to-500kb500 KB483,139YesYes
compress-image-to-1mb1,000 KB975,390YesYes

Every output clears the stricter of the two limits. That is deliberate: these pages treat N KB as N × 1,000 bytes, the smaller number, so that a file which passes here also passes a form counting the other way. It was not always so. Until 17 September 2026 the presets used 1,024, which meant a page called “compress to 100 KB” could hand you a 101,000-byte file — correct by its own arithmetic, rejected by a form checking for 100,000.

The part we got wrong

While measuring for this article we found the same confusion living inside our own interface. The compressors were targeting 1,000-byte kilobytes, but the function that writes the result on screen was still dividing by 1,024. So the tool did its job and then misreported it:

Target you typedBytes you gotWhat the page said (before)What the page says now
100 KB79,14177.3 KB79.1 KB
500 KB483,139471.8 KB483.1 KB
1 MB975,3900.93 MB0.98 MB

Neither column is a lie — 483,139 bytes genuinely is 471.8 KiB — but asking for 500 and being shown 471.8 makes it look as though the tool overshot its aim and wasted quality it did not need to spend. It had not. It was answering in a different unit than the question was asked in. As of today every size on this site is written in the same 1,000-byte kilobyte the compressors target, so the number you type, the number you read and the number the upload form counts are finally the same number.

Which kilobyte is on the other end?

You usually cannot tell from the form. But the defaults underneath it are documented, and they lean one way.

Where the limit livesWhat the documentation saysIn bytes
PHP upload_max_filesize“1M equals one Megabyte or 1048576 bytes. 1K equals one Kilobyte or 1024 bytes.”1,048,576 per “MB”
Django DATA_UPLOAD_MAX_MEMORY_SIZEDefault 2621440, described in the docs as “2.5 MB”2,621,440 — which is 2.62 MB decimal
nginx client_max_body_sizeDefault 1m; the documentation never states the multiplierNot documented

Read those rows together and the picture is clear enough. PHP does not merely use 1,024 — its manual stops to acknowledge the conflict, noting that what it calls a kilobyte is what the IEC standard calls a kibibyte. Django's default is a binary number wearing a decimal label: 2,621,440 bytes is exactly 2.5 × 1,048,576, yet the documentation calls it 2.5 MB, which in decimal it is not. And nginx, the most common thing standing in front of all of them, ships a default of 1m without ever defining what m multiplies by.

This is the useful finding: the systems checking your upload almost always count in 1,024s, while the label on the form, the number in the email from IT and the size your file manager shows may be counting in anything. You are not being told which. So the safe assumption is the one that survives both.

Your own computer is a third opinion

Before the file ever reaches a server, two programs on your machine have already disagreed about it. Windows File Explorer divides by 1,024 and writes the result as “KB”, so our 483,139-byte file appears there as 472 KB. macOS Finder has divided by 1,000 since OS X 10.6 and shows the same file as 483 KB. Neither is wrong, neither says which convention it used, and the two numbers differ by more than the width of some upload windows.

A browser, usefully, does not round at all. The size property of a selected file is the raw byte count, which is why every tool on this site can show you an exact figure: drop a file into any of them and the number you see is the number the server will count, not a rounded translation of it.

What to actually do

The short version

There are two kilobytes in common use, they differ by 2.4%, and that is comfortably wider than the margin most people leave when compressing to a limit. The software checking your upload probably counts in 1,024s; the label on the form probably does not say so. Compress to the smaller interpretation with a little room to spare and the question stops mattering, which is the only reliable way to win an argument between two definitions.

How this was measured

The four compression figures come from driving the live pages in headless Chrome through the DevTools protocol with the same 13.5 MB source image, capturing each download and reading its length in bytes — not the size reported in the interface, which is the very thing this article is about. The source is generated noise rather than a fixed file, so a repeat run lands a few hundred bytes either side of the numbers above; what does not move is which side of each limit the output falls on. The framework figures are quoted from the current PHP, Django and nginx documentation rather than from a running server, so they describe the shipped defaults; any given site may have changed them. The Windows and macOS figures are the documented rounding behaviour of each file manager applied to our measured byte count.

Tools used in this guide