JSONHandler.Handle returns nil even when the write to stdout failed #22

Open
opened 2026-08-10 14:50:43 +02:00 by clawbot · 0 comments
Collaborator

Found during the adversarial review of
#21
(#21 (comment)). Pre-existing,
not introduced by that PR.

JSONHandler.Handle discards the error from its write to stdout and returns
nil unconditionally. slog.Handler.Handle is declared to return an error
precisely so a failing sink can be reported; returning nil tells log/slog
the record was delivered when it was not.

This surfaced in that review as a lint question — the line is written
_, _ = fmt.Fprintln(...), which a newer golangci-lint flags and the repo's
pinned linter does not. Silencing the linter is not the fix and would bury the
defect. The defect is that a log line can vanish with nothing reporting it.

Definition of done

  • A failed write to the sink is returned from Handle rather than discarded, in
    every handler that writes to a sink, not only JSONHandler.
  • The behaviour is decided deliberately for the multiplex case: one child
    failing must not silently suppress delivery to its siblings, and the caller
    must still learn that something failed.
  • A test drives a handler whose sink returns an error and asserts the error
    reaches the caller. This requires the sink to be injectable; if it is not
    today, make it so rather than skipping the test.
  • Whatever is decided is written down in the README alongside the handler
    descriptions, since "logging can fail and here is how you find out" is
    caller-facing behaviour.
  • The repo's full check is green.

Implementation requirements

  • Do not paper over this by writing to a buffer that cannot fail.
  • Do not reintroduce any path back into the stdlib log package: that is the
    v1.0.0 deadlock in #18, and
    TestJSONHandlerDeadlock guards it.
  • Landing commit title must end with (closes #<this issue>).
Found during the adversarial review of https://git.eeqj.de/sneak/simplelog/pulls/21 (https://git.eeqj.de/sneak/simplelog/pulls/21#issuecomment-53518). Pre-existing, not introduced by that PR. `JSONHandler.Handle` discards the error from its write to stdout and returns `nil` unconditionally. `slog.Handler.Handle` is declared to return an `error` precisely so a failing sink can be reported; returning `nil` tells `log/slog` the record was delivered when it was not. This surfaced in that review as a lint question — the line is written `_, _ = fmt.Fprintln(...)`, which a newer golangci-lint flags and the repo's pinned linter does not. Silencing the linter is not the fix and would bury the defect. The defect is that a log line can vanish with nothing reporting it. ## Definition of done - A failed write to the sink is returned from `Handle` rather than discarded, in every handler that writes to a sink, not only `JSONHandler`. - The behaviour is decided deliberately for the multiplex case: one child failing must not silently suppress delivery to its siblings, and the caller must still learn that something failed. - A test drives a handler whose sink returns an error and asserts the error reaches the caller. This requires the sink to be injectable; if it is not today, make it so rather than skipping the test. - Whatever is decided is written down in the README alongside the handler descriptions, since &quot;logging can fail and here is how you find out&quot; is caller-facing behaviour. - The repo&#39;s full check is green. ## Implementation requirements - Do not paper over this by writing to a buffer that cannot fail. - Do not reintroduce any path back into the stdlib `log` package: that is the `v1.0.0` deadlock in https://git.eeqj.de/sneak/simplelog/issues/18, and `TestJSONHandlerDeadlock` guards it. - Landing commit title must end with ` (closes #<this issue>)`.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/simplelog#22