mecatui: shared diagnostics log silently discards output when another instance holds the lock
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 152
- Forks
- 16
- Avg merge
- 14h 48m
- Merged PRs (30d)
- 536
Description
Summary
The shared per-user diagnostics log ($XDG_STATE_HOME/mecatl/mecatui.log) is
single-writer, and when a second concurrently-running mecatui process can't
acquire the lock, its entire diagnostics stream is silently discarded — no
error, no fallback file, no indication anywhere that logging is a no-op for
that instance.
Where
cmd/mecatui/diaglog.go, openDiagLogWriterWithRetainer:
lock := flock.New(path+".lock",
flock.SetFlag(os.O_CREATE|os.O_RDWR|syscall.O_NOFOLLOW),
flock.SetPermissions(0o600),
)
locked, err := lock.TryLock()
if err != nil || !locked {
_ = lock.Close()
return io.Discard, noop, false
}
TryLock() is non-blocking. If another mecatui already holds
mecatui.log.lock, this call returns io.Discard as the writer — silently.
There's no retry, no fallback to a sibling/PID-suffixed file, and nothing
surfaced to the user or written anywhere that logging was disabled for this
run.
Reproduction
Confirmed empirically: with several mecatui instances already running
against the same workspace, I launched a new one (PID 52704) and, after it
had fully started, checked lsof -p 52704. It had opened zero file
handles matching mecatui.log or mecatui.log.lock — consistent with
TryLock losing the race and falling back to io.Discard without ever
attempting to open the file.
Why this matters
It's easy to accumulate several mecatui processes over time (leaving
sessions open across projects/terminals, forgetting to exit one before
starting another) — in the case that led to filing this, there were 13
concurrent mecatui processes against the same workspace, some running for
multiple days. Only whichever one won the lock race writes to the shared
log; every other instance's diagnostics — including the one you're actually
trying to debug — vanish with no indication that anything was suppressed.
This directly cost real debugging time: while investigating a separate
startup-latency issue (stacklok/mecatl#1695), the shared log
appeared to have "nothing" for the slow run, which looked like evidence
against several otherwise-correct hypotheses. The actual cause only became
visible once we passed --diagnostics-log <private path> to bypass the
shared, contended log entirely.
Suggested direction (not prescriptive)
When the shared log's lock can't be acquired, fall back to a PID-suffixed
sibling file (e.g. mecatui.<pid>.log) instead of io.Discard, so no
instance's diagnostics are silently lost — worst case, an operator now has to
check more than one file, which is strictly better than checking one file
that might be empty for reasons unrelated to the run itself.
🤖 Generated with Claude Code
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in cmd/mecatui/diaglog.go at openDiagLogWriterWithRetainer, reading how the lock and writer are created when TryLock fails. Reproduce the behavior with concurrent mecatui instances and inspect the existing diagnostics-log path handling. Done means a contending instance retains its diagnostics in a distinct fallback log instead of silently returning io.Discard.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- cli, observability
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 72/100