Symptom
You are moving a file between two datacentres. TCP checksums every segment, Ethernet has a 32-bit CRC on every frame, the disks have ECC, and the link is running over a protocol with its own integrity check. Four layers of protection.
The file arrives corrupt anyway.
The post-mortem finds it: a bad DIMM in a router, which corrupted the packet after the incoming frame’s CRC was verified and before the outgoing frame’s CRC was computed. Every check passed. Every check was checking a link, and the corruption did not happen on a link.
You add a fifth check somewhere in the middle, which is the intuitive response and the wrong one. The right response is a rule about where checks belong, and it explains why your four layers were never going to be enough regardless of how many you added.
Statement
The end-to-end argument (Saltzer, Reed, Clark, 1984). A function can be completely and correctly implemented only with the knowledge and help of the application standing at the endpoints of the communication system. Therefore providing that function as a feature of the communication system itself is not possible.
Sometimes an incomplete version of the function provided by the communication system may be useful as a performance enhancement.
Two claims, and both matter. The first is a statement about correctness: the lower layer cannot get it right, because it lacks information that only the endpoints have. The second is a concession about performance: the lower layer’s partial version may still pay for itself.
The failure mode people fall into is dropping the second sentence, which turns a careful engineering argument into a slogan against all in-network functionality.
Argument
The file transfer, worked through. The paper’s example is the cleanest statement of the case. Enumerate everywhere corruption can enter a file transfer from disk A to disk B:
- The disk on A returns bad data (bit rot beyond ECC).
- The file system or application on A corrupts it in memory.
- A’s network stack corrupts it before transmission.
- A router corrupts it in memory, between link checks.
- The link corrupts it (rare, and CRCs catch nearly all of it).
- B’s network stack corrupts it after reception.
- B’s application corrupts it before writing.
- B’s disk writes it incorrectly.
The network’s checksums protect step 5 and part of steps 3 and 6. They cannot protect 1, 2, 4, 7, or 8, because the network is not present for any of them — and step 4, memory corruption inside a router, occurs squarely between two link checks that both pass.
So no arrangement of hop-by-hop checks establishes that the file arrived intact. The only check that does is one computed by the application over the data it read, verified by the application against the data it wrote: an end-to-end checksum. And once you have that check, it covers all eight cases, including every case the link checks covered.
That is the structure of the argument in general. If the endpoints must do the check anyway for correctness, the lower layer’s version is redundant for correctness — its only remaining justification is performance.
The performance justification is real and the paper says so. Consider a link with a 1% packet loss rate carrying a 1,000-packet transfer. Without hop-by-hop retransmission, the probability the whole transfer succeeds is $0.99^{1000} \approx 4 \times 10^{-5}$, so end-to-end retry alone means retrying the entire transfer roughly 25,000 times. With per-link retransmission the loss is repaired locally and the end-to-end check almost never fires.
So the lower-layer function is justified exactly when it makes the common case cheap, and never when it is offered as a guarantee. This is why 802.11 does link-layer retransmission — wireless loss rates make end-to-end recovery prohibitively slow — while wired Ethernet does not, and both decisions are the same principle applied to different numbers.
The generalisation to system design. The argument is about networks by accident of origin. What it really says is: a function should be implemented at the layer that has the information needed to implement it correctly, and duplicating it below is an optimization requiring separate justification.
Encryption. Link encryption protects each hop, and the data is plaintext in every intermediate node. Only end-to-end encryption gives the property users believe they have. This is why TLS supplanted IPsec-everywhere for application traffic, and why “encrypted in transit” between your load balancer and your service is a different claim from “the user’s message is private”.
Deduplication and delivery guarantees. A message queue offering exactly-once delivery cannot deliver it, because the consumer might crash after receiving and before committing, and the queue cannot see that boundary. Only the consumer, which knows what “processed” means for its own state, can make the operation idempotent. Every exactly-once claim in a broker is at-least-once plus an end-to-end idempotency key that the application supplies, and vendors who describe this as a broker feature are describing the performance half while implying the correctness half.
Transactions. A distributed transaction coordinator cannot know that a business operation is complete, because completeness is defined by the application. Sagas push the compensation logic to the endpoint that knows it.
Data integrity at rest. ZFS and Btrfs checksum at the file-system layer, above the disks’ own ECC, for exactly the reason above: the disk’s check does not cover the cable, the controller, or the host’s memory. Every serious study of silent data corruption finds errors that per-device checks structurally cannot see.
Why the internet is shaped the way it is. This argument is the reason IP provides only best-effort delivery and pushes reliability, ordering, and congestion control into TCP at the hosts. The consequence was not a technical detail but the deployment model of the entire internet: a network that guarantees nothing needs to know nothing about the applications running over it, so new applications require no change to the network. The web, video streaming, and everything since deployed without asking any router’s permission. A network that offered per-application guarantees would have had to be modified for each one.
Forbids
Claiming a correctness guarantee from a lower layer that lacks the information. In-network checksums do not guarantee file integrity. Broker delivery semantics do not guarantee processing semantics. Link encryption does not guarantee confidentiality of a message.
Omitting an end-to-end check because a lower layer “already does it”. The lower layer covers a subset of the failure modes, and the uncovered ones are exactly the ones your instrumentation cannot see.
Building application semantics into the network. A middlebox that must understand the application breaks whenever the application changes, which is why deep-packet-inspection appliances are the most reliable source of “our new feature broke on one customer’s network” reports.
Treating hop-by-hop redundancy as additive. Four link checks do not compose into an end-to-end check. They compose into four link checks.
Does not forbid
It does not say lower layers should do nothing, and this is the misreading that gets the paper cited against things it explicitly endorses. The second sentence of the statement is a performance carve-out, and the authors meant it. TCP’s own checksum is a lower-layer partial check that the paper’s logic approves of, because catching corruption early avoids retransmitting an entire stream, even though it does not establish end-to-end integrity.
It does not condemn CDNs, caches, or middleboxes as a class. A CDN is an in-network optimization that does not claim to provide a correctness property the endpoints need. The end-to-end argument is entirely compatible with caching; it only objects when the cache is relied upon for a guarantee, such as consistency, that only the origin and client can define.
It does not forbid QoS or in-network congestion signalling. ECN, active queue management, and traffic shaping are performance mechanisms whose failure degrades service rather than breaking correctness. The argument is about where guarantees live, not about where mechanism lives.
It does not make link-layer reliability wrong. Wi-Fi’s link-layer ARQ is a textbook-correct application of the performance clause, and disabling it in the name of end-to-end purity would make wireless TCP unusable.
It does not mean “put everything in the application”. The argument identifies the layer with the necessary information, which is not always the topmost one. Congestion control lives in the transport because the transport observes the signals; moving it into every application produced the modern mess of application-level retry storms, which is this principle misapplied.
Boundary
- Trust changes the endpoints. If the endpoint itself is untrusted — DRM, attestation, corporate policy enforcement — the party who wants the guarantee is not at an endpoint, and the argument gives them no comfort. Most of the political fights about network neutrality are really disagreements about who counts as an endpoint.
- Performance can dominate. When the lower-layer version is enormously cheaper, it wins in practice even where the argument says correctness lives above. TCP offload and hardware checksums are the standard case.
- The endpoints must be capable. Constrained IoT devices may genuinely be unable to do end-to-end crypto, and gateways doing it on their behalf are a conscious violation with a stated threat model.
- “The application” can be hard to locate. In a browser, is the endpoint the TLS stack, the JavaScript, or the user? Different answers give different guarantees, and phishing is what happens when the user is the endpoint and the check is at the TLS stack.
- Latency-sensitive recovery. For interactive media, end-to-end retry is useless because the retransmitted frame arrives too late; forward error correction in the network is the right answer, and the argument’s cost-benefit clause is how you get there.
The sentence to keep: the layer that can define the property is the layer that must check it, and everything below is an optimization that owes you a measurement.