Skip to content

BuildNot yet confirmed elsewhere1 publisher3 min readPublished

Five days of silence: a launchd job that only failed when a human ran it

launchd does not set LANG, so the scheduled run passed and the hand-run died with exit 127. The line it died on was the one that sends the failure alert.

The Engineer · Build desk

How we use AISend a correction

Illustration accompanying Five days of silence: a launchd job that only failed when a human ran it
Generated illustration

What happened

  • launchd starts jobs in the C locale because it does not set LANG, while the same script run from a terminal inherits ja_JP.UTF-8.
  • The scheduled morning run passed every day; running the script by hand died immediately with exit 127.
  • The line that died sat in the failure notifier, so a failed Threads post never produced its Discord alert.
  • Posting stayed down for five days with nothing reaching the author's phone.
  • The same locale assumption was present in five repositories, according to the writeup's headline.

Why it matters

  • constraint Because the pipeline's success test asks only whether a stock file was written, no number of passing runs can register that publishing has stopped.
  • exposure Alert code is the one part of an automation that runs only after something else breaks, which leaves it unverified until the day it is load-bearing.
  • decision Operators have to pick which absence they alarm on, because errors that never reach the notifier will only surface as missing output.
  • precedent With Japanese log and notification text as the trigger, every new script written in that house inherits the same trap until the job environment is pinned.

Exit 127 at your own prompt does not read as a defect in the script. It reads as a typo. That is exactly the reflex the author describes: you assume you invoked it wrong, and you move on [5].

The scheduler's thin environment was already understood in that codebase, just not all of it. Phase 1 of the 528-line, 12-phase generator explicitly extends PATH with nvm and homebrew before doing any work [10][13], which is the code you write after launchd has failed to find a binary on you once. A missing LANG [1] is the same family of omission with none of the noise. Nothing is absent from disk. The scheduled process simply gets a different locale than the shell you tested in [2].

Then there is where the line sat. It was inside the failure notifier [18], and a notifier only executes after something else has already broken, so a run of green days tells you nothing at all about whether it works [11].

One seam in the writeup is worth naming. It reports the C-locale scheduled run passing and the interactive run dying [3][4], but the five-day outage requires the notification line to have died where launchd ran it, not at a terminal [18][6]. The post does not reconcile those two, and it does not show the failing line, so why a UTF-8 locale is the fatal one and C is not stays outside the evidence [17].

The monitoring conclusion survives either reading. The design's own definition of success is whether a stock file landed in content/article, deliberately cut loose from the Zenn deploy so a jammed publish cannot stop generation [8]. That part worked. The two daily slots kept firing across the window [7], roughly ten scheduled invocations [15], and every one of them was correct to say it had done its job [3]. The signal was accurate and had nothing to do with what had stopped.

The check that would have caught it is an alarm on absence rather than on error: nothing posted since yesterday, or a marker file older than some threshold. Against a stated target of 30 articles a month, one a day [9], five quiet days is about five posts not shipped [16], on the pipeline the author says sits under ¥1.2M a month of revenue [20]. Error alerts only cover failures that manage to reach the notifier intact. Everything upstream of it, including the notifier itself, needs the other kind.

The blast radius here is a property of writing style, not of the bug. Any script that logs or notifies in Japanese under launchd could stand on the same mine [12], which is how a single assumption about the environment ends up sitting in five repositories at once [19]. The author's own summary of the last six months is the useful part: a system begins rotting the moment it is built, and it does not tell you [14].

What to watch

  • Whether the author publishes the failing line, which would settle why the UTF-8 locale dies and the C locale does not.
  • Whether the fix is a LANG export per script or an EnvironmentVariables entry in the launchd plists, and whether the other four repos get the same treatment.
  • Whether the next stoppage is caught by a heartbeat check rather than by someone running the command by hand.

Clarity's read

What the record supports and how the coverage leans. The claims behind it follow.

Reality

Evidence30
Adoption12
Hype gap+38
Incentives68
Confidence42
Why these scores

Claim ledger

Ranked by verification strength, evidence, and original report placement.

  1. [1]

    launchd does not set LANG, so scripts running under launchd execute in the C locale.

  2. [2]

    When the same script is run from an interactive terminal, the shell inherits LANG=ja_JP.UTF-8.

  3. [3]

    The 8:00 scheduled run, in the C locale, passed without incident.

    ReportedSupportedView cited source

Sources

1 independent publisher whose own reporting we read for this story.

  1. dev.to

    1 article · August 26, 2026

    5 Days of Silent Failures: A launchd Locale Bug That Was Hiding in 5 Repos

Share your take

Let Clarity write the post for you.

Signed-in readers get a short post drafted on this story in the register they choose — narrative, analytical, or a direct position — editable to the last word before it goes anywhere. The share buttons at the top of this story work without an account.

Topics and entities

Follow any of these and your For You feed starts watching them — no settings page required.

Topics

  • Shell locale and encoding bugsFollow
  • launchd scheduled job environmentFollow
  • Silent failure and alerting pathsFollow
  • LLM content automation pipelinesFollow
  • Solo-operator production reliabilityFollow
Loading related stories