Live data from Hacker News

Cloudflare outage on November 18, 2025 post mortem

blog.cloudflare.com

791–800 of 953 posts

Re: Cloudflare outage on November 18, 2025 post mortem

#791
post #716

Why does cloudflare allow unwraps in their code? I would've assumed they'd have clippy lints stopping that sort of thing. Why not just match with { ok(value) => {}, Err(error) => {} } the function already has a Result type. At the bare minimum they could've used an expect("this should never happen, if it does database schema is incorrect"). The whole point of errors as values is preventing this kind of thing.... It w…

unwrap() is only the most superficial part of the problem. Merely replacing `unwrap()` with `return Err(code)` wouldn't have changed the behavior. Instead of "error 500 due to panic" the proxy would fail with "error 500 due to $code". Unwrap gives you a stack trace, while retuned Err doesn't, so simply using a Result for that line of code could have been even harder to diagnose. `unwrap_or_default()` or other ways of…

We don't know what the surrounding code looks like, but I'd expect it handles the error case that's expressed in the type signature (unless they `.unwrap()` there too).

The problem is that they didn't surface a failure case, which means they couldn't handle rollouts of invalid configurations correctly.

The use of `.unwrap()` isn't superficial at all -- it hid an invariant that should have been handled above this code. The failure to correctly account for and handle those true invariants is exactly what caused this failure mode.

Re: Cloudflare outage on November 18, 2025 post mortem

#792

Earlier quoted context omitted.

The type system is for asserting assumptions like "this cannot fail". You don't crash at all.

Most properties of programs cannot be validated at compile time and must be checked at runtime. But you’re still missing it. Crashing is not bad. It’s good. It’s how you leverage OS level security and reliability.

This wasn't a runtime property that could not be validated at compile time. And you don't need to fall back on "OS level security and reliability" when your type system is enforcing an application-level invariants.

In fact I'd argue that crashing is bad. It means you failed to properly enumerate and express your invariants, hit an unanticipated state, and thus had to fail in a way that requires you to give up and fall back on the OS to clean up your process state.

[edit]

Sigh, HN and its "you're posting too much". Here's my reply:

> Why? The end user result is a safe restart and the developer fixes the error.

Look at the thread your commenting on. The end result was a massive world-wide outage.

> That’s what it’s there for. Why is it bad to use its reliable error detection and recovery mechanism?

Because you don't have to crash at all.

> We don’t want to enumerate all possible paths. We want to limit them.

That's the exact same thing. Anything not "limited" is a possible path.

> If my program requires a config file to run, crash as soon as it can’t load the config file. There is nothing useful I can do (assuming that’s true).

Of course there's something useful you can do. In this particular case, the useful thing to do would have been to fall back on the previous valid configuration. And if that failed, the useful thing to do would be to log an informative, useful error so that nobody has to spend four hours during a worldwide outage to figure out what was going wrong.

Re: Cloudflare outage on November 18, 2025 post mortem

#793
post #277

Earlier quoted context omitted.

> graph-heavy code Could you share some more details, maybe one fully concrete scenario? There are lots of techniques, but there's no one-size-fits-all solution.

Sure, these days I'm mostly working on a few compilers. Let's say I want to make a fixed-size SSA IR. Each instruction has an opcode and two operands (which are essentially pointers to other instructions). The IR is populated in one phase, and then lowered in the next. During lowering I run a few peephole and code motion optimizations on the IR, and then do regalloc + asm codegen. During that pass the IR is mutated a…

One normal "trick" is phantom typing. You create a type representing indices and have a small, well-audited portion of unsafe code handling creation/unpacking, where the rest of the code is completely safe.

The details depend a lot on what you're doing and how you're doing it. Does the graph grow? Shrink? Do you have more than one? Do you care about programmer error types other than panic/UB?

Suppose, e.g., that your graph doesn't change sizes, you only have one, and you only care about panics/UB. Then you can get away with:

1. A dedicated index type, unique to that graph (shadow / strong-typedef / wrap / whatever), corresponding to whichever index type you're natively using to index nodes.

2. Some mechanism for generating such indices. E.g., during graph population phase you have a method which returns the next custom index or None if none exist. You generated the IR with those custom indexes, so you know (assuming that one critical function is correct) that they're able to appropriately index anywhere in your graph.

3. You have some unsafe code somewhere which blindly trusts those indices when you start actually indexing into your array(s) of node information. However, since the very existence of such an index is proof that you're allowed to access the data, that access is safe.

Techniques vary from language to language and depending on your exact goals. GhostCell [0] in Rust is one way of relegating literally all of the unsafe code to a well-vetted library, and it uses tagged types (via lifetimes), so you can also do away with the "only one graph" limitation. It's been awhile since I've looked at it, but resizes might also be safe pretty trivially (or might not be).

The general principle though is to structure your problem in such a way that a very small amount of code (so that you can more easily prove it correct) can provide promises that are enforceable purely via the type system (so that if the critical code is correct then so is everything else).

That's trivial by itself (e.g., just rely on option-returning .get operators), so the rest of the trick is to find a cheap place in your code which can provide stronger guarantees. For many problems, initialization is the perfect place (e.g., you can bounds-check on init and then not worry about it again) (e.g., if even bounds-checking on initialization is too slow then you can still use the opportunity at initialization to write out a proof of why some invariant holds and then blindly/unsafely assert it to be true, but you then immediately pack that hard-won information into a dedicated type so that the only place you ever have to think about it is on initialization).

[0] https://plv.mpi-sws.org/rustbelt/ghostcell/

Re: Cloudflare outage on November 18, 2025 post mortem

#794

Earlier quoted context omitted.

Most properties of programs cannot be validated at compile time and must be checked at runtime. But you’re still missing it. Crashing is not bad. It’s good. It’s how you leverage OS level security and reliability.

This wasn't a runtime property that could not be validated at compile time. And you don't need to fall back on "OS level security and reliability" when your type system is enforcing an application-level invariants. In fact I'd argue that crashing is bad. It means you failed to properly enumerate and express your invariants, hit an unanticipated state, and thus had to fail in a way that requires you to give up and fal…

> I'd argue that crashing is bad.

Why? The end user result is a safe restart and the developer fixes the error.

> fall back on the OS to clean up your process state.

That’s what it’s there for. Why is it bad to use its reliable error detection and recovery mechanism?

> It means you failed to properly enumerate and express your invariants

We don’t want to enumerate all possible paths. We want to prune them.

If my program requires auth info to run, crash as soon as it can’t load it. There is nothing useful I can do (assuming that’s true).

Re: Cloudflare outage on November 18, 2025 post mortem

#795
post #633

Earlier quoted context omitted.

Right, but the point isn't to make errors impossible; the point is to have them be 1) less likely to write, and 2) easier to spot on review. People's biggest complaints about golang's errors: 1. You have to _TYPE_OUT_ what to do on EVERY.SINGLE.ERROR. SOO BOORING! 2. They clutter up the code and make it look ugly. Rust is so much cleaner and more convenient (they say)! Just add ?, or .unwrap()! Well, with ".unwrap()"…

Eh, I'm not convinced. 1. Culturally, using `unwrap` is an omerta to Rust developers in the same way `panic` is an omerta to Go devs; 2. In the Rust projects I've seen there is usually a linter rule forbidding `unwrap` so you can't use it in production

> omerta

Unfortunately none of the meanings Wikipedia knows [1] seems to fit this usage. Did you perhaps mean "taboo"?

I disagree that "unwrap()" seems as scary as "panic()", but I will certainly agree to sibling commenters have a point when they say that "bar, _ := foo()" is a lot less scary than "unwrap()".

[1] https://en.wikipedia.org/wiki/Omerta_(disambiguation)

Re: Cloudflare outage on November 18, 2025 post mortem

#796
post #210

Earlier quoted context omitted.

Well… we have a culture of transparency we take seriously. I spent 3 years in law school that many times over my career have seemed like wastes but days like today prove useful. I was in the triage video bridge call nearly the whole time. Spent some time after we got things under control talking to customers. Then went home. I’m currently in Lisbon at our EUHQ. I texted John Graham-Cumming, our former CTO and current…

> I texted John to see if he wanted to post it to HN. He didn’t reply after a few minutes so I did Damn corporate karma farming is ruthless, only a couple minute SLA before taking ownership of the karma. I guess I'm not built for this big business SLA.

We're in a Live Fast Die Young karma world. If you can't get a TikTok ready with 2 minutes of the post modem drop, you might as well quit and become a barista instead.

Re: Cloudflare outage on November 18, 2025 post mortem

#797

Earlier quoted context omitted.

Well… we have a culture of transparency we take seriously. I spent 3 years in law school that many times over my career have seemed like wastes but days like today prove useful. I was in the triage video bridge call nearly the whole time. Spent some time after we got things under control talking to customers. Then went home. I’m currently in Lisbon at our EUHQ. I texted John Graham-Cumming, our former CTO and current…

You call this transparency, but fail to answer the most important questions: what was in the burrito? Was it good? Would you recommend?

I DON'T see this as transparency. There is ZERO mention of the burrito in the post-mortem document itself.

0/10, get it right the first time, folks. (/s)

Re: Cloudflare outage on November 18, 2025 post mortem

#800

Earlier quoted context omitted.

There are many self-hosted alternatives to protect against botnet. We don't have to use cloudflare. Everthing is under their control!

> There are many self-hosted alternatives to protect against botnet. What would some good examples of those be? I think something like Anubis is mostly against bot scraping, not sure how you'd mitigate a DDoS attack well with self-hosted infra if you don't have a lot of resources? On that note, what would be a good self-hosted WAF? I recall using mod_security with Apache and the OWASP ruleset, apparently the Nginx ve…

>What would some good examples of those be?

There is haproxy-protection, which I believe is the basis of Kiwiflare. Clients making new connections have to solve a proof-of-work challenge that take about 3 seconds of compute time.

Enterprise: https://www.haproxy.com/solutions/ddos-protection-and-rate-l...

FOSS: https://gitgud.io/fatchan/haproxy-protection

Post reply on HN