The single-instance guard worked perfectly and bricked the game

15 September 2026

PixelTrader should not run twice at once. Both copies would hold the same credentials, both would place orders into the same account, and each would reconcile its own idea of the positions against a brokerage that was being changed underneath it by the other. That is a genuinely bad failure.

So: a single-instance guard, using a named mutex — a Windows primitive that one process can hold and a second cannot.

What I got wrong

I wrote it to fail closed. If the guard could not be established, the program refused to start.

That is the correct instinct for a safety mechanism and the wrong one here, and the difference is worth being precise about. Failing closed is right when the thing you are guarding is dangerous and the guard is the only thing standing between you and the danger. It is wrong when a failure of the guard says nothing about whether the danger is present.

A mutex can fail to be acquired for reasons that have nothing to do with a second instance: permissions, session isolation, security software, a stale handle from a process that did not exit cleanly. In all of those cases there is no second copy running. There is just a guard that could not answer, and a program that now will not launch at all.

Which is what happened. The game stopped starting, on a machine with exactly one copy of it.

The distinction: the guard's job is to detect a second instance. When it cannot run, it has not detected a second instance — it has failed to look. Treating "I could not check" as "the dangerous thing is happening" is a different claim, and it is the one that took the program down.

The fix

Fail open. If the mutex cannot be established, log it and start anyway. A guard that cannot answer degrades to no guard, rather than to a locked door.

This is emphatically not the posture the money rails take. The position caps, the day-loss stop and the account breaker all fail closed, and they should: when those cannot verify that a trade is safe, refusing the trade is the correct answer, and the cost of refusing is a missed round. The cost of a window that will not open is the entire program.

Same word, "safety". Two completely different calculations underneath it.

Previous: A pair of parentheses broke the build after it had already succeeded

All devlog posts