DEV Community

John Wick
John Wick

Posted on

A Failed Validation Shouldn't Permanently Break Your API

Summer Bug Smash: Clear the Lineup 🐛🛹

This is a submission for *DEV's Summer Bug Smash: Clear the Lineup** powered by Sentry.*

A Failed Validation Shouldn't Permanently Break Your API

Project Overview

StayPresent is an open-source Python library for running and supervising long-running bots.

Its staypresent.run() function starts the web server, launches bot processes, and is intentionally designed to be called only once during the lifetime of a Python process.

While auditing the initialization logic, I found an edge case where a simple configuration mistake could permanently prevent the application from starting.


Bug Fix or Performance Improvement

Internally, StayPresent tracks whether run() has already been called.

This prevents multiple servers from accidentally being started in the same process.

The bug wasn't the existence of this protection—it was when the protection became active.

The internal "already running" flag was set before validating the user's configuration.

If validation failed because of something as simple as an invalid bot path or port number, run() correctly raised an exception.

However, the flag remained set.

Even after fixing the configuration, every later call immediately failed because StayPresent believed it had already been started.

In reality, no server had ever launched.

The application had effectively poisoned its own state during a failed initialization.


The Fix

The initialization sequence was reordered.

Configuration is now fully validated before the one-time initialization flag is claimed.

Only once validation succeeds—and immediately before startup actually begins—is the flag marked as used.

If validation fails, callers can simply correct their configuration and call run() again.

The framework remains in exactly the same state it was in before the failed attempt.


Why It Matters

Fail-fast validation is a good design principle.

But validation failures should never partially modify internal state.

If an operation doesn't succeed, it shouldn't leave the system believing that it did.

This change makes StayPresent's initialization logic behave much more predictably while preserving its existing API.


Conclusion

One lesson this bug reinforced is that successful validation and successful initialization are two different milestones.

Internal state should only change once you're certain the operation can actually proceed.

A small change in initialization order eliminated a surprising edge case and made the framework much more intuitive for developers.


Code

GitHub Repository

https://github.com/StayElite/StayPresent

Changelog (Fixed in v1.5.9)

https://github.com/StayElite/StayPresent/blob/main/CHANGELOG.md

Commit

https://github.com/StayElite/StayPresent/commit/66e07394e0a6e3192bd5c3a0849bfffea4f1e1b4

Top comments (0)