Wiki · Evidence & Verdicts
Receipt — OBS "chronic safe mode / locale error" ROOT CAUSE + durable fix — 2026-07-14
How to read this page
Three ways to read this page. Precise is the document itself, exactly as it is written in the repository. Plain and Clear were written for this website to help you meet that document — they are about it. They are not it, and they are not evidence.
Eighty-seven dated pages: receipts, pre-registrations, handoffs, validation records and review verdicts. A receipt is written at the moment a piece of work was checked. It names what was claimed, the commit and the seed, what was actually run, and the outcome in one of a small set of controlled words. Then it names what the work did not achieve. That last part is what makes it a receipt rather than an announcement. A pre-registration is the same discipline run in advance: the conditions that would count as a pass and the conditions that would falsify the claim are written down before the run, so neither can be adjusted once the numbers arrive.
That is why so many small dated stubs are an audit trail rather than noise. No one of them is meant to be a good read. The value is in the sequence and in the dates, because you can watch a prediction be registered, then the run happen, then the verdict land — sometimes against the prediction. Pages here record a falsified result, a rejected fix, a retracted overclaim, and a green receipt that turned out not to be reproducible from the commit that carried it. A record that carried only successes would be worth a good deal less than this one.
A gentle way in is to read a pre-registration first, so the shape becomes familiar, then a result page, then one of the corrections. This section sits off the main navigation on purpose: it is the record you check the rest of the site against, not the place to begin.
What it is not: documentation, and not a summary. Nothing here has been tidied in hindsight. Every entry reads as of its date, a later entry may overturn an earlier one, and the presence of a page is not a claim that its result stood.
Your browser cannot switch reading levels, so the document itself is shown.
Precise — the source document
This is the document. Rendered from the repository at the commit above, with nothing rewritten for the web. A gate re-renders it on every deploy and fails the build if a single byte differs.
Verdict: RESOLVED, Class A. The OBS install was never broken. Two self-inflicted causes stacked; both are fixed durably. OBS bound :4455 in 4 seconds from a clean start, no dialog.
Cause and effect (honest, no invented theory)
- Effect observed: OBS showed an
Error: Failed to find locale/en-US.inidialog, sat in Safe Mode ("Skipping module 'obs-websocket', not on safe list"), and never bound :4455. - NOT the cause (disproven by evidence): the install.
data\obs-studio\locale\en-US.iniexists (96032 bytes), 75 locale files present, obs-websocket.dll + its locale present, OBS 32.1.2 intact. - Real cause #1 — orphaned .sentinel: OBS drops
.sentinel\run_<uuid>on start and deletes it ONLY on a clean exit. The agent's spawn-loop stacked dozens of OBS instances and then force-killed them repeatedly; each force-kill left an orphanrun_<uuid>-> next start declared "crash detected" -> Safe Mode -> obs-websocket skipped -> no :4455. - Real cause #2 — wrong working directory: when the agent hand-launched OBS via
cmd /c start(a workaround for a sandbox path filter), the working directory was the repo, not the OBS bin dir. OBS resolves..\..\data\obs-studio\localerelative to cwd, so it "couldn't find" a file that was right there.studio_up.ps1launches with-WorkingDirectory (Split-Path $OBS)(the bin dir), which is exactly why OBS worked all morning and broke only under hand-launch.
The durable fix
studio_up.ps1now removes the WHOLE.sentineldirectory on every start (was: only its children), so a force-killed OBS ALWAYS returns clean with no dialog. Root cause documented inline.- Operating rule: OBS is only ever launched by
studio_up.ps1(correct working dir). Never bycmd /c start, never hand-launched. Never force-killed — graceful close only (-Stop). - The spawn loop that caused the force-kills in the first place is already dead (gate
door-storm-breakers: reads-never-actuate +UNI_STUDIO_UPmutex + window dedup).
Proof (verbatim, this heal)
sentinel removed: gone · obs running before: 0
OBS :4455 up: True (waited ~4s) · OBS Error dialog present: False
OBS log: [obs-websocket] WebSocket server is enabled, starting...
full studio: 6/6 ports UP (4455/9997/8098/8099/8443/8095)
verify_overlays exit=0 (COLONY carries all 4 overlays)
studio doors open: 5/5 · journey current=feature_test · command-center windows: 1 (no flood)
sha256 0461eba5dbdd4fb4 — of the original file, so what was ingested stays checkable.
Plain — written for this website, not the source document
A short record of one fault being tracked down and fixed. A piece of software kept starting in a limited mode and complaining that a file was missing. The file was not missing. The record is careful to say what was not the cause, and to list the evidence for that, before giving the two things that were. One was leftover marker files from processes that had been killed rather than closed. The other was launching the program from the wrong folder, so it looked for its own files in the wrong place. That hand launch was itself a workaround for a sandbox path filter.
Plain · written 2026-08-01 by claude-opus-5 · not yet checked by a person · about the document whose sha256 is 0461eba5dbdd4fb4
Clear — written for this website, not the source document
A receipt, meaning a file that records what was run: one fault, its cause, and the fix, written down afterwards and marked resolved. It opens by clearing the innocent party. The installation was never broken, and the page lists what it checked in order to say so, which is the difference between a diagnosis and a theory.
The first real cause is a marker file the program leaves behind while it runs and removes only on a clean exit. Something had been starting many copies and then force-killing them, so the markers piled up, and each new start read them as evidence of a crash and dropped into a limited mode with a component switched off. That is why a port never opened.
The second cause is a working directory. When the program was launched by hand, as a workaround for a sandbox path filter, it started from the wrong folder, and it looks for part of its files relative to wherever it was started. The file it could not find was there all along. The normal launch script starts it from the right folder, which is why the fault appeared only under the hand launch.
The fix has three parts. The launch script now clears the leftover markers completely rather than partly. An operating rule says the program is only ever started by that script, and only ever closed gracefully rather than killed. And the loop that caused the repeated killing is already gone. The page ends with the output of the run that came out clean, quoted rather than summarised.
Clear · written 2026-08-01 by claude-opus-5 · not yet checked by a person · about the document whose sha256 is 0461eba5dbdd4fb4