When Does a Rewrite Make Sense?

Part 3 of 3: Is It Memory Safe? | Languages Evolve | When Does It Make Sense?


Parts 1 and 2 explored the costs of rewrites and the fact that languages evolve. This part looks at the evidence: cases where rewrites introduced real problems, and a case where starting over in a different language might genuinely be the better path.


The most famous [w]rap in the software industry#

Date: November 18, 2025
Impact: Approximately six hours of degraded service across Cloudflare’s entire network
Root cause: A single .unwrap() call on a bounds check

Cloudflare’s FL2 proxy layer is written in Rust. A database permission change caused a feature file to double in size, exceeding an assumed limit of 200 entries. The Rust code called .unwrap() on the bounds check instead of handling the error. The process panicked and propagated to every machine on the network.

This was a logic error, not a memory safety issue. The Rust compiler cannot distinguish between .unwrap() (panic on failure) and .unwrap_or_default() (handle failure gracefully), because both are valid Rust. The compiler accepted the code that caused the outage. It just ensured the outage was memory-safe.

Cloudflare had genuine technical reasons for building FL2 in Rust. But the incident illustrates something worth internalizing: memory safety does not prevent outages.


Canonical’s coreutils: The silent breakage#

Date: October 2025
Impact: Ubuntu 25.10 automatic security updates stopped working
Root cause: Missing feature in a “drop-in replacement”

Canonical replaced GNU coreutils with uutils, a Rust rewrite. The Rust date command accepted the -r flag through the argument parser but never implemented it. The flag was silently ignored. Systems running unattended upgrades stopped checking for security updates because the timestamp comparison returned the wrong value.

This was a missing feature in a rewrite that was supposed to be a drop-in replacement. The GNU implementation was stable enough that it never needed a regression test for this flag. The Rust rewrite inherited that coverage gap and shipped it to production.


sudo-rs: Security vulnerabilities in a security tool#

Date: 2025
Impact: Multiple security vulnerabilities in the tool responsible for privilege escalation
Root cause: Rewrite-era bugs in a security-critical component

Canonical replaced GNU sudo with sudo-rs, a Rust rewrite. Multiple vulnerabilities followed. CVE-2025-46717 allowed unprivileged users to probe for file existence in restricted directories. CVE-2025-46718 let users with limited sudo privileges enumerate other users’ sudo permissions. Then in November 2025, USN-7867-1 disclosed that sudo-rs mishandled password input on timeout, potentially leaking partially typed passwords to standard input, and mishandled targetpw and rootpw settings when creating timestamp files, allowing a local attacker to bypass authentication in certain configurations.

A tool rewritten for memory safety introduced security bugs that the existing C version did not have. GNU sudo has been audited, fuzzed, and tested through decades of adversarial use. sudo-rs started that process from the beginning. This is the iteration cost described in Part 2 made concrete.


Performance regressions: cksum, sort, base64#

Date: 2025
Impact: Slower builds, hanging pipelines, degraded performance
Root cause: Optimizations not yet discovered for real-world workloads

The Rust cksum utility was measurably slower than the C original. The Rust sort command failed on large single-line files. The Rust base64 implementation was slower until an Ubuntu developer noticed and the upstream team patched it.

These are not Rust-specific issues. They are rewrite-specific issues. The C implementations had decades of optimization for real-world workloads. The Rust rewrites started from the specification and had not yet encountered the same range of inputs.


The upstream propagation problem#

These incidents share a structural concern. When Canonical replaces coreutils in Ubuntu’s repositories, that change propagates through the dependency chain:

  • Every container image based on ubuntu:25.10 picks up the new utilities
  • Every server running unattended upgrades installs the replacements
  • Every CI pipeline pulling from Ubuntu repositories builds against the new code
  • Every deployment that depends on Ubuntu packages inherits the new behavior

None of these consumers chose to adopt the rewrite. A date -r command that worked last week might silently return the wrong value this week. Nothing changed in the consumer’s environment; the upstream changed the implementation.


chardet: When the clean room has windows#

Date: 2026
Impact: Community fracture, legal uncertainty for downstream consumers
Root cause: AI-assisted rewrite used to relicense from LGPL to MIT

Part 1 described how chardet’s maintainer used AI to rewrite the library and relicense it from LGPL to MIT. What happened next illustrates why AI-assisted rewrites are not just a technical concern.

The AI agent’s plan explicitly referenced the original LGPL source. That detail alone undermines the clean-room claim, but the broader fallout went further. The original author objected publicly. Bruce Perens weighed in on the legal questions. Alternative forks appeared under novel licenses. The downstream effect is still unfolding: projects that depended on chardet under LGPL now have a MIT-licensed dependency they never agreed to, shipped under the same package name.

The response from the wider open source community has been structural. Zig, Gentoo, and QEMU have banned AI-generated contributions entirely. These are not reactions to bad code. They are reactions to the inability to verify where AI-generated code came from and what license obligations it carries.

This is the intersection of the two problems this series describes: the rewrite pattern erodes communities, and AI removes the safeguards that used to keep the pattern in check.


So when does a rewrite actually make sense?#

The cases above illustrate what can go wrong: technically, structurally, and socially. But not all rewrites are equal. Some produce genuinely better tools.

Cloudflare’s Rust proxy layer, despite the .unwrap() outage, was motivated by real operational limitations in nginx that Cloudflare had outgrown. That is a defensible reason to start over.

And then there are cases where the original technology stack is itself the problem.

I have been following nullclaw, an AI agent tool written in Zig. It does what OpenClaw does, but without the TypeScript runtime, without Node, without npm, and without the dependency tree that comes with all of that. It is compiled, minimal, and fast.

I have written positively about OpenClaw’s governance. OpenAI putting it in a foundation was the right decision. But the technology underneath is TypeScript, and anyone who has managed Node dependencies in production knows what that means. nullclaw in Zig is an interesting counterexample to the pattern described in this series: sometimes a rewrite in a different language produces something meaningfully better, not because the new language is fashionable, but because the original stack was genuinely the wrong tool for the job.

The difference is intent. A rewrite motivated by “this language is better” tends to rediscover old problems. A rewrite motivated by “this architecture is wrong for this problem” tends to produce something new.


A framework, not a verdict#

This series is not an argument against Rust or against rewrites. It is an attempt to ask better questions:

  • What gets lost? Community knowledge, contributor relationships, edge-case handling that took years to accumulate.
  • What happens to the license? A rewrite can dissolve the licensing choices that original contributors relied on, especially when it ships under the same package name.
  • Could the original improve instead? Languages evolve. Rust itself evolved dramatically. The source language might fix the problem that motivated the rewrite.
  • Is this the best use of this energy? The talent in the Rust ecosystem is extraordinary. Rewriting solved problems is one use of that talent. Solving unsolved problems is another.
  • Is the architecture actually wrong? When the original stack genuinely cannot serve the problem, a rewrite makes sense. nullclaw replacing TypeScript with Zig for an agent runtime is a different proposition than rewriting coreutils for memory safety.

There is one more argument worth addressing. The White House and CISA have actively pushed for adoption of memory-safe languages. A reader could reasonably say the rewrite pattern is not ecosystem culture but government policy. That framing deserves acknowledgment, but it does not change the analysis. Policy recommendations do not eliminate the community costs described in this series; they just add a justification for incurring them. And policy does not always get the technical details right, as we have seen before. The question is still whether a full rewrite is the best way to achieve the safety goals, or whether incremental improvements to existing tools would get there with less collateral damage.

The Rust community has the talent to build things that have never existed. The question is whether the rewrite pattern is the best expression of that talent, or whether some of that energy might create more value pointed in a different direction.

A note on why Rust appears so often in this series: Rust’s approach to memory safety is genuinely strong, arguably the strongest of any systems language. This series is not a critique of the language. It is a critique of the assumption that memory safety alone justifies rewriting tools that already work, and of an ecosystem where GitHub stars speak louder than decades of production hardening.


Part 3 of 3: Is It Memory Safe? | Languages Evolve | When Does It Make Sense?