beginner 3 min answer Multiple choice

A mobile app ships a release with a defect that crashes on launch for users in one country. The team is confident because the release included a remote kill switch for the new feature. It does not help. Which mistake does this most likely reflect?

kill-switchfeature-flagsmobilestartuprollback
Pick one
Show the full answer Hide the answer

The mechanism

A kill switch is only a control if it is evaluated before the thing it kills runs. Startup is where this is most often violated, because the natural implementation fetches configuration during initialisation and the new feature also initialises during startup. If the crash happens while the app is building its object graph, reading a database migration, or parsing a cached payload, the flag fetch has not completed, and the app dies before it can learn it should not have tried.

The fix is ordering, and it is cheap: a small, separately-parsed configuration blob read from local storage on the very first line of startup, with the previous value cached on disk, before any feature initialises. The remote fetch updates that cache for next launch. This gives you a switch that works on a device that is offline, which matters because a crash loop means the app may never live long enough to complete a network call.

The second requirement is that the crash path itself must be recoverable without the network. The standard mechanism is a launch-failure counter written before initialisation and cleared once the app reaches a stable state. After 3 consecutive failures the app enters a safe mode: skip optional initialisation, clear the local cache, use the last known good configuration. This is the client-side equivalent of a rollback, and on mobile it is the only rollback you have, because a released build cannot be recalled.

Why the other options fail

  • The flag was cached and propagated slowly. A real and common problem — this is why flag changes need a stated worst-case propagation time — but it would produce a delay of minutes to hours in some users' behaviour, not a total failure to help. The users here never reach the code that reads the flag.
  • Nobody enabled it in production. Possible, and it is an operational error that a rollout checklist catches. It does not explain why a correctly-configured flag would still be useless, which is the structural point worth learning.
  • App store review delayed the fix. True, and it is why the kill switch existed. It explains why the team needed the switch rather than why the switch failed.

When this is less of a risk

A server-driven screen or a feature behind a network call is far easier to kill, because the server can simply stop returning it, and nothing on the client has to be correct. That is a real argument for putting risky new surfaces behind server-supplied content when you can. The startup path is the one place where you cannot, and it is also the place where failure is total rather than partial.

What the disk-cached switch costs is worth stating: a configuration read before anything else is initialised cannot use your dependency-injected client, your logging, or your normal parsing, so it is written twice — once properly, once as a few hundred bytes of boring code with its own tests. That duplication is the price of a control that works on a device with no network, and a store review queue measured in days is why you pay it.