Go: stop RPC client logging expected errors#609
Conversation
There was a problem hiding this comment.
Pull request overview
Adjusts Go’s internal JSON-RPC client shutdown behavior to avoid logging an expected “closed pipe/file already closed” read error during teardown, reducing noisy stderr output when copilot.Client stops the CLI subprocess.
Changes:
- Add
errors/osimports to support error classification. - Suppress logging for read-loop header errors when the underlying error is
os.ErrClosed(in addition toio.EOF).
| // Only log unexpected errors (not EOF or closed pipe during shutdown) | ||
| if err != io.EOF && c.running.Load() { | ||
| if err != io.EOF && !errors.Is(err, os.ErrClosed) && c.running.Load() { | ||
| fmt.Printf("Error reading header: %v\n", err) | ||
| } | ||
| return |
There was a problem hiding this comment.
readLoop now suppresses os.ErrClosed when failing to read the header, but the message-body read path still unconditionally logs Error reading body on shutdown. Since Stop() closes stdout specifically to unblock readLoop, io.ReadFull can also return os.ErrClosed/io.EOF during normal teardown and will still print an expected error. Consider applying the same “unexpected only” guard (including c.running.Load()) to the body read error handling so shutdown stays quiet regardless of whether the loop is in header or body read.
You might see
Error reading header: read |0: file already closedprinted during client shutdown on Linux. This happens becausecopilot.Clientkills the CLI subprocess and calls the RPC client'sStopmethod, which closes the subprocess's stdout. Meanwhile, the RPC client has a read loop blocked on a pipe connected to the subprocess's stdout. That loop breaks with an error:io.EOFif the process teardown wins the race,os.ErrClosedif the pipe close does. The comment anticipates this but the guard around printing the error expects onlyio.EOF. So, simple fix to avoid logging the expected error condition is to addos.ErrClosedto the guard.