Reported by the cattbox manager, verified against this repo's tags by the dispatcher. Filed here because it affects every repo in the org: CODE_STYLEGUIDE_GO.md mandates this library for all Go repos.
The deadlock
JSONHandler — selected whenever stdout is not a TTY, i.e. every container and every CI run — writes via the stdlib log package. slog.SetDefault redirects stdlib log back into the same handler. The first log line recurses and deadlocks on the stdlib logger's mutex.
cattbox's make test hung to its 30s timeout with exactly that cycle in the trace.
This is not a degradation, it is a hang. A binary using v1.0.0stops on its first log statement in production, while passing a developer's local run — because an interactive terminal selects ConsoleHandler instead. Local green, container hang.
Why the fix is unreachable
Tags on this repo, read from the API just now:
1.0.1 9121da9aaed27db195db998185e7f215c143fd3e <- the fix, NOT resolvable by Go
v1.0.0 31c9ed52cb8f68d690dc57caecc1b8f7a0e5f0bc <- the deadlocking version
Go requires the leading v for a semver tag, so 1.0.1 is invisible to the module proxy. v1.0.0 is the only version go get sneak.berlin/go/simplelog can resolve, which means the obvious command hands every consumer the deadlocking release.
Fix
One command, and it unblocks every consuming repo at once:
git tag v1.0.1 9121da9aaed2 && git push origin v1.0.1
Nothing else changes — same commit, additional tag. Note the dispatcher can create this tag via the Gitea API on request, but has not done so unilaterally, since publishing a version tag changes what every downstream repo resolves and that is the owner's call.
Interim workaround for consuming repos
Pin the pseudo-version naming the fix commit, rather than go get:
Same module, hash recorded in go.sum, no vendoring and no hand-rolled substitute. cattbox is using exactly this today (its #25 tracks bumping to a real tag once one exists).
Definition of done
v1.0.1 exists and go get sneak.berlin/go/simplelog@v1.0.1 resolves the fix commit.
A consuming repo demonstrates a log line emitted from a non-TTY context without hanging — a container run, not a local terminal, since a TTY takes the other code path and cannot reproduce the bug.
Consuming repos that pinned the pseudo-version are told they can move to the tag.
Reported by the cattbox manager, verified against this repo's tags by the dispatcher. Filed here because it affects every repo in the org: `CODE_STYLEGUIDE_GO.md` mandates this library for all Go repos.
## The deadlock
`JSONHandler` — selected whenever stdout is not a TTY, i.e. **every container and every CI run** — writes via the stdlib `log` package. `slog.SetDefault` redirects stdlib `log` back into the same handler. The first log line recurses and deadlocks on the stdlib logger's mutex.
cattbox's `make test` hung to its 30s timeout with exactly that cycle in the trace.
This is not a degradation, it is a hang. A binary using `v1.0.0` **stops on its first log statement in production**, while passing a developer's local run — because an interactive terminal selects `ConsoleHandler` instead. Local green, container hang.
## Why the fix is unreachable
Tags on this repo, read from the API just now:
```
1.0.1 9121da9aaed27db195db998185e7f215c143fd3e <- the fix, NOT resolvable by Go
v1.0.0 31c9ed52cb8f68d690dc57caecc1b8f7a0e5f0bc <- the deadlocking version
```
Go requires the leading `v` for a semver tag, so `1.0.1` is invisible to the module proxy. **`v1.0.0` is the only version `go get sneak.berlin/go/simplelog` can resolve**, which means the obvious command hands every consumer the deadlocking release.
## Fix
One command, and it unblocks every consuming repo at once:
```sh
git tag v1.0.1 9121da9aaed2 && git push origin v1.0.1
```
Nothing else changes — same commit, additional tag. Note the dispatcher can create this tag via the Gitea API on request, but has not done so unilaterally, since publishing a version tag changes what every downstream repo resolves and that is the owner's call.
## Interim workaround for consuming repos
Pin the pseudo-version naming the fix commit, rather than `go get`:
```
sneak.berlin/go/simplelog v1.0.1-0.20260208172955-9121da9aaed2
```
Same module, hash recorded in `go.sum`, no vendoring and no hand-rolled substitute. cattbox is using exactly this today (its #25 tracks bumping to a real tag once one exists).
## Definition of done
- `v1.0.1` exists and `go get sneak.berlin/go/simplelog@v1.0.1` resolves the fix commit.
- A consuming repo demonstrates a log line emitted from a non-TTY context without hanging — a container run, not a local terminal, since a TTY takes the other code path and cannot reproduce the bug.
- Consuming repos that pinned the pseudo-version are told they can move to the tag.
The tag is done: v1.0.1 points at 9121da9 (the same commit as 1.0.1), and v1.0.2 (7f0cd5d) exists since 2026-09-29. sneak pointed out in chat (2026-10-03 12:1x UTC) that this was already done; the fleet kept asking him without checking the tags. Sorry.
The rest of the definition of done is fleet work: a non-TTY run from a consuming repo, and telling repos that pinned the pseudo-version (cattbox, sneak/cattbox#25) to move to a tag. simplelog and cattbox are both paused, so it is queued for when either resumes. Reassigned to clawbot.
Model: opus-5-5
The tag is done: `v1.0.1` points at `9121da9` (the same commit as `1.0.1`), and `v1.0.2` (`7f0cd5d`) exists since 2026-09-29. sneak pointed out in chat (2026-10-03 12:1x UTC) that this was already done; the fleet kept asking him without checking the tags. Sorry.
The rest of the definition of done is fleet work: a non-TTY run from a consuming repo, and telling repos that pinned the pseudo-version (cattbox, https://git.eeqj.de/sneak/cattbox/issues/25) to move to a tag. simplelog and cattbox are both paused, so it is queued for when either resumes. Reassigned to clawbot.
Model: opus-5-5
sneak
was unassigned by clawbot2026-10-03 14:12:46 +02:00
clawbot
self-assigned this 2026-10-03 14:12:46 +02:00
Run from a consuming repo with no terminal: cattbox branch issue-25-simplelog-v1.0.2 at commit 13d5c69, with simplelog v1.0.2. The image built by make docker, started with docker run -d and no -t, printed its startup lines as JSON with their attributes and was still running when its logs were read. First line:
cattbox moves from the pseudo-version to the v1.0.2 tag in sneak/cattbox#45.
Model: opus-5-5
Run from a consuming repo with no terminal: cattbox branch `issue-25-simplelog-v1.0.2` at commit `13d5c69`, with simplelog `v1.0.2`. The image built by `make docker`, started with `docker run -d` and no `-t`, printed its startup lines as JSON with their attributes and was still running when its logs were read. First line:
```
{"Level":"INFO","Message":"Starting cattbox","PC":7876316,"Time":"2026-10-03T12:31:50.337678561Z","arch":"amd64","version":"13d5c69"}
```
cattbox moves from the pseudo-version to the `v1.0.2` tag in https://git.eeqj.de/sneak/cattbox/pulls/45.
Model: opus-5-5
Done. The deadlock fix is commit 869b7ca (merged as 9121da9), on both main and next, and TestJSONHandlerDeadlock guards it. v1.0.1 resolves to that commit, the cattbox container run with no terminal is recorded above, and cattbox moved to the v1.0.2 tag in sneak/cattbox#45 (merged). Closing.
Model: opus-5-5
Done. The deadlock fix is commit `869b7ca` (merged as `9121da9`), on both `main` and `next`, and `TestJSONHandlerDeadlock` guards it. `v1.0.1` resolves to that commit, the cattbox container run with no terminal is recorded above, and cattbox moved to the `v1.0.2` tag in https://git.eeqj.de/sneak/cattbox/pulls/45 (merged). Closing.
Model: opus-5-5
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Reported by the cattbox manager, verified against this repo's tags by the dispatcher. Filed here because it affects every repo in the org:
CODE_STYLEGUIDE_GO.mdmandates this library for all Go repos.The deadlock
JSONHandler— selected whenever stdout is not a TTY, i.e. every container and every CI run — writes via the stdliblogpackage.slog.SetDefaultredirects stdliblogback into the same handler. The first log line recurses and deadlocks on the stdlib logger's mutex.cattbox's
make testhung to its 30s timeout with exactly that cycle in the trace.This is not a degradation, it is a hang. A binary using
v1.0.0stops on its first log statement in production, while passing a developer's local run — because an interactive terminal selectsConsoleHandlerinstead. Local green, container hang.Why the fix is unreachable
Tags on this repo, read from the API just now:
Go requires the leading
vfor a semver tag, so1.0.1is invisible to the module proxy.v1.0.0is the only versiongo get sneak.berlin/go/simplelogcan resolve, which means the obvious command hands every consumer the deadlocking release.Fix
One command, and it unblocks every consuming repo at once:
Nothing else changes — same commit, additional tag. Note the dispatcher can create this tag via the Gitea API on request, but has not done so unilaterally, since publishing a version tag changes what every downstream repo resolves and that is the owner's call.
Interim workaround for consuming repos
Pin the pseudo-version naming the fix commit, rather than
go get:Same module, hash recorded in
go.sum, no vendoring and no hand-rolled substitute. cattbox is using exactly this today (its #25 tracks bumping to a real tag once one exists).Definition of done
v1.0.1exists andgo get sneak.berlin/go/simplelog@v1.0.1resolves the fix commit.clawbot referenced this issue2026-08-10 14:39:53 +02:00
clawbot referenced this issue2026-09-03 15:06:57 +02:00
done, 1.0.1 and 1.0.2 tagged. gitea release made
The tag is done:
v1.0.1points at9121da9(the same commit as1.0.1), andv1.0.2(7f0cd5d) exists since 2026-09-29. sneak pointed out in chat (2026-10-03 12:1x UTC) that this was already done; the fleet kept asking him without checking the tags. Sorry.The rest of the definition of done is fleet work: a non-TTY run from a consuming repo, and telling repos that pinned the pseudo-version (cattbox, sneak/cattbox#25) to move to a tag. simplelog and cattbox are both paused, so it is queued for when either resumes. Reassigned to clawbot.
Model: opus-5-5
Run from a consuming repo with no terminal: cattbox branch
issue-25-simplelog-v1.0.2at commit13d5c69, with simplelogv1.0.2. The image built bymake docker, started withdocker run -dand no-t, printed its startup lines as JSON with their attributes and was still running when its logs were read. First line:cattbox moves from the pseudo-version to the
v1.0.2tag in sneak/cattbox#45.Model: opus-5-5
Done. The deadlock fix is commit
869b7ca(merged as9121da9), on bothmainandnext, andTestJSONHandlerDeadlockguards it.v1.0.1resolves to that commit, the cattbox container run with no terminal is recorded above, and cattbox moved to thev1.0.2tag in sneak/cattbox#45 (merged). Closing.Model: opus-5-5