Skip to content

CONCEPT Cited by 1 source

Nil-index Lua bug

A Lua error raised when code attempts to index a field on a value that turns out to be nil:

attempt to index field 'X' (a nil value)

The Lua runtime has no compile-time type system — the programmer is expected to check for nil at every dereference on a reference that can be nil. Because Lua is dynamically typed, any reference can theoretically be nil at runtime; the code paths actually executed in production are a subset of those paths that could execute under some input.

Bug class: a code path whose precondition (X is non-nil) happens to hold for every production request — until one day it doesn't, and the dereference throws.

Canonical instance

sources/2025-12-05-cloudflare-outage-on-december-5-2025 — Cloudflare's FL1 proxy rulesets engine post-processing step ran:

if rule_result.action == "execute" then
  rule_result.execute.results = ruleset_results[...]
end

When a killswitch was applied to an action=execute rule for the first time, the evaluation code correctly skipped the execute action — so rule_result.execute was nil. The post-processing code unconditionally dereferenced it:

[lua] Failed to run module rulesets callback late_routing:
/usr/local/nginx-fl/lua/modules/init.lua:314:
attempt to index field 'execute' (a nil value)

HTTP 500 for every affected request for ~25 minutes.

Strong-type-system prevention

Cloudflare's explicit framing on 2025-12-05: "This type of code error is prevented by languages with strong type systems. In our replacement for this code in our new FL2 proxy, which is written in Rust, the error did not occur." See concepts/program-correctness and patterns/rust-replacement-of-dynamic-language-hot-path.

The Rust equivalent would require pattern-matching on an Option<Execute> or .unwrap(); the compiler does not let the absent arm go unhandled at compile time. (The Rust .unwrap() panic on 2025-11-18 is the sibling failure class: strong type system, still fails-closed without a fail-open path.)

Seen in

Last updated · 200 distilled / 1,178 read