> ## Documentation Index
> Fetch the complete documentation index at: https://www.floe.one/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# How Floe checks that each file arrived intact

> How Floe checks each received file against the size and SHA-256 its sender sent, what the check mark and the Verified row mean, and what they do not prove.

Floe checks every file it receives before it lets you keep it, and tells you when every file
passed. This page explains the two checks, the mark that shows they passed, and what that mark
does and does not prove.

<h2 id="the-short-version">
  The short version
</h2>

The receiving app compares each file with the size the sender announced, and with the sender's
[SHA-256](/docs/glossary#sha-256) when the sender provides one. A SHA-256 is a short fingerprint worked
out from a file's bytes, which changes if any byte changes. A file that fails either check is
deleted and the transfer stops. When every file passes both, the app shows a mark that says so,
which means the files arrived intact, not that they are safe to open.

<h2 id="the-size-check">
  The size check
</h2>

Every receiver runs this check on every file. The sender announces each file's size before its
first byte, and when the sender marks the file as finished, the receiver compares what arrived
with that size. The two must be equal. A file that is short was cut off, and a file that is long
was not the file the sender described.

Either way the receiver discards the file, tells the sender why, and stops the transfer, so files
queued behind it do not arrive either. Files that finished before it are kept. See
[a file did not appear at all](/docs/troubleshooting#a-file-did-not-appear-at-all).

Floe Desktop and `floe receive` do not wait for the end of a file that is too long. They stop at
the first piece of data that would take a file past its announced size, so a sender cannot fill
the disk.

A browser receiver that is given no size at all accepts the file as it stands. One given a size
it cannot read, such as a negative number, stops the transfer before it keeps any data. Every
current Floe sender announces a size.

<h2 id="the-sha-256-check">
  The SHA-256 check
</h2>

The size check cannot see a file whose bytes changed while its length did not. The SHA-256 check
can.

The sender computes a SHA-256 of each file as it sends it, and sends that right after the file's
last byte. The receiver computes its own SHA-256 of what arrived and compares the two:

* Floe Desktop and `floe receive` compute it while they write the file, and compare before the
  file takes its final name. They never read the file back from disk.
* The web app computes it once the file's last byte has arrived, on the copy it holds for you to
  save. The status reads "Verifying file 2 of 3" while it works.

A file that does not match is never kept. Floe Desktop and `floe receive` delete it before it has
its final name, the web app discards it, the sender is told that a file did not match, and the
transfer stops. Files that finished before it are kept. A SHA-256 that arrives but cannot be read
counts as a mismatch, not as a missing one. For what each side shows, see the troubleshooting
entries for [the browser](/docs/troubleshooting#a-file-did-not-match-what-was-sent),
[the command line](/docs/troubleshooting#a-file-did-not-match-the-sha-256), and
[the desktop app](/docs/troubleshooting#they-discarded-a-file).

Senders provide a SHA-256 from `floe` 1.11.0, from Floe Desktop 0.3.0, and from the web app at
floe.one. An older sender provides none, and the receiver then relies on the size check alone.

Floe never shows the SHA-256 itself, and there is nothing for the two people to compare. Each app
shows only whether every file matched.

<h3 id="when-a-browser-runs-out-of-time">
  When a browser runs out of time
</h3>

A browser computes the SHA-256 in the background, and with a very large file or a slow device the
file can be finished before its SHA-256 is. Floe then lets the file through unchecked rather than
fail a transfer whose bytes all arrived:

* A browser that is **sending** waits for a file's SHA-256 at most 45 seconds after the file's
  last byte, then sends the file without one. It cannot wait longer, because Floe Desktop and
  `floe receive` give up on a transfer that goes 60 seconds without data.
* A browser that is **receiving** with more files to come checks a file for at most 90 seconds,
  then keeps it unchecked so the next file can start. The sender stops waiting for the next file
  to be accepted after 120 seconds. The last file of a transfer has nothing waiting behind it, so
  it gets as long as its size needs: the time the file would take at 10 MB per second, plus 30
  seconds.

Floe Desktop and the [CLI](/docs/glossary#cli) compute the SHA-256 as they read and write the file, so
they have no such wait. The frames and fields behind both checks are in
[Transfer protocol](/docs/reference/transfer-protocol#integrity).

<h2 id="delivery-confirmation">
  Delivery confirmation
</h2>

A sender can finish sending before the receiver has finished saving. The last file may still be
crossing the connection, or the receiving app may still be checking it and moving it into place.
So what "sent" means depends on whether the receiver reports back.

| Sending from | To | The send is finished when |
| - | - | - |
| `floe send` or Floe Desktop | `floe receive` or Floe Desktop, with both sides on `floe` 1.11.0 or later or Floe Desktop 0.3.0 or later | The receiving app says it has saved every file, after its checks. A file it deleted or could not save at the last moment ends the send as a failure with the reason. |
| `floe send` 1.11.0 or later, or Floe Desktop 0.3.0 or later | A browser | The receiving page says it holds every file, after its checks. A file it could not keep at the last moment, such as one a browser ran out of memory for, ends the send as a failure with the reason. |
| `floe send` or Floe Desktop | An older `floe` or Floe Desktop, or a browser when the sending app is older than the versions above | Everything has left the sending device. |
| The web app's Send page | Any receiver | Everything has left the browser, and the status reads "All Files Sent!". If the receiving app then reports a file it refused, the page replaces that status with the failure and its reason. |
| A [request link](/docs/glossary#request-link)'s page, or `floe send --to` | Floe Desktop | Floe Desktop says it has saved every file. Nothing less counts. |

On the first two rows and the last, the finished state is the receiver's word: the files are saved
on the other device, or held by the receiving page, ready to save. It reads `Sent` in the summary of
`floe send`, "Sent 3 items" in Floe Desktop, and "ALL 3 FILES ARRIVED" on a request link's page. On
the two rows between, it means the data left your device, which is not the receiver's word.

Where the sender waits for the receiver's word, the wait has no time limit of its own: it lasts
as long as the connection does. If the receiving device vanishes instead of answering, `floe send`
and Floe Desktop give the connection up about 30 seconds after its last packet. The send then ends
as a failure, never as a success. See the troubleshooting entries for
[the command line](/docs/troubleshooting#the-connection-closed-before-the-receiver-confirmed-delivery)
and
[the desktop app](/docs/troubleshooting#the-connection-dropped-before-the-transfer-finished).

<h2 id="what-you-see-in-each-app">
  What you see in each app
</h2>

When every file of a transfer passed the SHA-256 check, the app says so, on both sides where it
can. No app shows the SHA-256 itself. In these docs this is the
[SHA-256 matched](/docs/glossary#sha-256-matched) mark.

| Where | What you see when every file's SHA-256 matched |
| - | - |
| Web app, receiving | A green check mark in front of "3 files received". |
| Web app, the Send page | A green check mark in front of "All Files Sent!", and the status turns green. |
| Web app, a request link's page | “Their app reports every file's SHA-256 matched.” on the card “ALL 3 FILES ARRIVED”. |
| `floe receive` | A `Verified` row that reads `SHA-256 matched`, under `Received` in the summary. [floe receive](/docs/cli/receive#output) shows the whole summary. |
| `floe send` | The same `Verified` row, between `Sent` and `Time`. |
| `floe send --to` | The line `Their app reports every file's SHA-256 matched.` after the line that says the files arrived. |
| Floe Desktop, sending | A green check mark in front of "Sent 3 items". |
| Floe Desktop, receiving with a code or a link | A green check mark in front of "Saved to" and the folder. |
| Floe Desktop, a request link | A green check mark after the heading, for example "RECEIVED 12 FILES, 38.0 GB", and beside the folder in that drop's row in History. |

The web app's main page and Floe Desktop draw the check mark without words. A screen reader reads
it as "SHA-256 matched". A request link's page writes a sentence instead, and the CLI a row.

On the sending side the mark is the receiver's report, not a check your own app made: your app
sent the SHA-256, and the other side says every file matched it. The web app's Send page says
"All Files Sent!" as soon as the last byte leaves, before that report, so its check mark is gray
for a moment and turns green when the report arrives. See
[When it finishes](/docs/web-app/sending#when-it-finishes).

<h2 id="when-there-is-no-mark">
  When there is no mark
</h2>

The mark is all or nothing. It shows only when every file of the transfer arrived and every one
matched, so a single unchecked file removes it for the whole transfer.

No mark does not mean a file is damaged. Every file that was kept passed the size check, and a
file that fails the SHA-256 check is deleted, never kept without a mark. A transfer finishes
without the mark when:

* The sender sent no SHA-256 for some file. Either it is a `floe` older than 1.11.0 or a Floe
  Desktop older than 0.3.0, or it is a browser that had not finished computing one
  [when its time ran out](#when-a-browser-runs-out-of-time).
* The receiver is a browser that had not finished checking some file when its time ran out, or
  that could not run the check.
* You are the sender and the receiver is an older `floe` or Floe Desktop, which reports that the
  files arrived but not whether they matched.
* Not every file arrived, because the transfer stopped partway.
* One side is a web app that someone hosts themselves and that runs an older version. See
  [What an older web app shows](/docs/self-hosting/operations#older-web-app-versions).

| Where | What you see without the mark |
| - | - |
| Web app, receiving or the Send page | A gray check mark in place of the green one. On the Send page "All Files Sent!" stays gray. |
| Web app, a request link's page | Only the line that says the files arrived. |
| `floe send` and `floe receive` | No `Verified` row in the summary. |
| `floe send --to` | Only the line that says the files arrived. |
| Floe Desktop, sending or receiving with a code or a link | A gray check mark in place of the green one. |
| Floe Desktop, a request link | No check mark after the heading or in History. |

<h2 id="if-a-file-fails-a-check">
  If a file fails a check
</h2>

The receiving side names the check that failed. Files that finished before the one named are kept
in every app.

| Message | What it means | What to do |
| - | - | - |
| `Incomplete file "<name>": received <n> of <m> bytes`, then a sentence on what went wrong, in the web app | That file's size did not match what the sender announced, so the browser discarded it and stopped the transfer. | Ask the sender to send that file and the ones after it again. See [a file did not appear at all](/docs/troubleshooting#a-file-did-not-appear-at-all). |
| `incomplete file "<name>": received <n> of <m> bytes`, from `floe receive` | The file ended before its announced size, so it was deleted and the receive stopped. | The same. |
| `sender exceeded the announced size of "<name>"`, from `floe receive` | More data arrived than the sender announced, so the receive stopped at that point and the file was deleted. | The same. |
| “A file arrived incomplete and wasn't kept”, in Floe Desktop | That file ended before its announced size, so it was deleted and the receive stopped. | The same. |
| `transfer failed: sender exceeded the announced size of "<name>"`, in Floe Desktop | More data arrived than the sender announced, so the receive stopped at that point and the file was deleted. | The same. |
| “A file did not match what was sent, so it was discarded. Ask the sender to try again.”, in the web app | The bytes did not match the sender's SHA-256. | See [the browser entry](/docs/troubleshooting#a-file-did-not-match-what-was-sent). |
| `a file did not match the SHA-256 the sender computed, so it was not kept`, from `floe receive` and Floe Desktop | The bytes did not match the sender's SHA-256, so the file was deleted before it took its final name. | See [the command line entry](/docs/troubleshooting#a-file-did-not-match-the-sha-256). |

<h2 id="what-the-checks-prove">
  What the checks prove and what they do not
</h2>

A file that passed both checks has exactly the bytes the sending app read and sent. That rules out
a file cut short and a file whose bytes changed between the two apps.

<Warning>
  The mark means the files arrived intact. It does not mean they are safe to open. Floe does not
  scan files for malware.
</Warning>

The checks also do not prove:

* **Who sent the file.** The SHA-256 travels over the same connection as the file, so it is not a
  signature and says nothing about who is at the other end. That question belongs to the
  connection itself. See [Encryption](/docs/how-it-works/encryption#what-it-does-not-protect-against).
* **That the copy on your disk is still intact.** Floe Desktop and `floe receive` take the SHA-256
  while they write and never read the file back, and the web app checks the copy it holds before
  your browser saves it. Damage that happens on your disk afterward is outside the check. See
  [Known limitations](/docs/how-it-works/known-limitations#the-sha-256-check-covers-the-transfer-not-your-disk-afterward).
* **That the sender chose the right file.** The check covers what was sent, not what was meant.


## Related topics

- [Send your first file](/docs/quickstart.md)
- [Receive files in your browser](/docs/web-app/receiving.md)
- [Send files peer-to-peer with Floe](/docs/introduction.md)
- [File size limits and the 2 GB relay cap](/docs/how-it-works/2gb-limit.md)
- [Frequently asked questions](/docs/faq.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.