Skip to content

fix(daemon): recover acceptLoop panics#1305

Open
mvanhorn wants to merge 1 commit into
floatpane:masterfrom
mvanhorn:fix/daemon-acceptloop-panic-recover-1119
Open

fix(daemon): recover acceptLoop panics#1305
mvanhorn wants to merge 1 commit into
floatpane:masterfrom
mvanhorn:fix/daemon-acceptloop-panic-recover-1119

Conversation

@mvanhorn
Copy link
Copy Markdown
Contributor

What?

Adds a top-level defer func() { recover(); log }() to (*Daemon).acceptLoop so a panic in the accept goroutine logs with a stack trace instead of taking down the whole daemon.

Closes #1119

Why?

daemon/daemon.go:120 launches go d.acceptLoop() with no panic recovery. A panic inside the loop (or in addClient / daemonrpc.NewConn) propagates up and the runtime aborts the process. The sync loop, IDLE watcher, and connected clients all die with it. The issue notes the same risk applies to the prior recovery fixes (#979 / #980 / #981).

The recovery pattern matches the existing one at main.go:4089: log the panic with a runtime/debug.Stack() trace and let the goroutine exit. The daemon stops accepting new connections after a recovered panic, but already-connected clients and the background sync loop keep running, which is what the issue body asks for.

Verification

  • go build ./... clean
  • go vet ./daemon/... clean
  • go test ./daemon/... passes
  • Diff is +6 lines in daemon/daemon.go (one import, one defer block)

Closes floatpane#1119.

`go d.acceptLoop()` is launched without a recover, so a panic inside
the goroutine (e.g. nil deref in `Accept`-returned conn state or in
`addClient`) takes down the entire daemon. The maintainer noted the
same risk applies to floatpane#979 / floatpane#980 / floatpane#981.

Add a top-level defer with the existing pattern from main.go:4089:
log the panic with a stack trace before letting the goroutine exit.
The daemon stops accepting new connections after recovery, but existing
clients and the sync loop survive, which is the documented expectation.
@mvanhorn mvanhorn requested a review from a team as a code owner May 18, 2026 05:41
@floatpanebot floatpanebot added bug Something isn't working ci CI / build pipeline labels May 18, 2026
Copy link
Copy Markdown
Member

@floatpanebot floatpanebot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @mvanhorn! Please fix the following issues with your PR:

  • Title: Is too long (45 characters). The PR title must be strictly under 40 characters.

@floatpanebot floatpanebot added area/daemon Daemon / RPC size/XS Diff: 0–10 lines labels May 18, 2026
@mvanhorn mvanhorn changed the title fix(daemon): add panic recovery to acceptLoop fix(daemon): recover acceptLoop panics May 18, 2026
@floatpanebot floatpanebot dismissed their stale review May 18, 2026 05:52

Formatting issues have been resolved. Thank you!

@andrinoff andrinoff requested a review from FromSi May 18, 2026 09:04
Comment thread daemon/daemon.go
if r := recover(); r != nil {
log.Printf("daemon: acceptLoop panic recovered: %v\n%s", r, debug.Stack())
}
}()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not match the expected behavior: acceptLoop exits, while it should restart/continue running. At minimum, we could wrap the current loop body in an inner func inside the for loop, move the existing logic there, and place the defer func() recovery inside that inner function.

From issue:

Wrap the goroutine body in a recover that logs and restarts the loop.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/daemon Daemon / RPC bug Something isn't working ci CI / build pipeline size/XS Diff: 0–10 lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BUG: daemon acceptLoop has no panic recovery

3 participants