wavetermdev/waveterm · warning
timeout sending response
Error message
timeout sending response
What it means
SendResponse marshals the response and writes it to the WshRpc OutputCh; if the handler's context is done before the write completes, the response could not be delivered and this error is returned. The requester has typically timed out, cancelled, or the connection closed.
Source
Thrown at pkg/wshutil/wshrpc.go:707
defer handler.close()
}
if handler.reqId == "" {
return nil
}
msg := &RpcMessage{
ResId: handler.reqId,
Data: data,
Cont: !done,
}
barr, err := json.Marshal(msg)
if err != nil {
return err
}
select {
case handler.w.OutputCh <- barr:
return nil
case <-handler.ctx.Done():
return fmt.Errorf("timeout sending response")
}
}
func (handler *RpcResponseHandler) SendResponseError(err error) {
defer func() {
panichandler.PanicHandler("SendResponseError", recover())
}()
if handler.done.Load() {
return
}
defer handler.close()
if handler.reqId == "" {
return
}
msg := &RpcMessage{
ResId: handler.reqId,
Error: err.Error(),
}View on GitHub (pinned to a4447c1563)
Solutions
- Check handler.ctx.Err() before doing expensive work or sending; abort early if already done.
- Increase the client-side timeout for slow operations so the response window is sufficient.
- Treat this as a benign late-response race in the handler (log debug, skip retry) since the caller is gone.
- Ensure responses are sent promptly; move heavy work before the response window or use streaming with per-chunk sends.
Example fix
// before
func respond(w *wshutil.WshRpc, handler *wshutil.RpcResponseHandler, data any) error {
return handler.SendResponse(data, true)
}
// after
func respond(w *wshutil.WshRpc, handler *wshutil.RpcResponseHandler, data any) error {
if handler.ctx.Err() != nil { return handler.ctx.Err() }
return handler.SendResponse(data, true)
} Defensive patterns
Strategy: try-catch
Validate before calling
if handler.ctx.Err() != nil {
return handler.ctx.Err() // skip sending; requester already gone
} Try / catch
if err := handler.SendResponse(data, true); err != nil && strings.Contains(err.Error(), "timeout sending response") {
// requester timed out or disconnected; log at debug, do not retry
return nil
} Prevention
- Keep handler work fast or stream incrementally so responses fit in the window.
- Raise client-side TimeoutMs for slow operations.
- Check handler ctx before beginning expensive response preparation.
- Treat late-response failures as benign races rather than errors to retry.
When it happens
Trigger: Server handler calls SendResponse after the requester's timeout already fired (unregisterRpc removed the pending entry and cancelled); connection shutdown draining context; OutputCh blocked while the handler ctx expires.
Common situations: Slow handler finishing just past the client timeout; client disconnects mid-request; long streaming operations whose per-chunk sends exceed the remaining deadline.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- failed to list workspaces: %v
- failed to list blocks from all %d workspace(s)
- reinstalling connection: %w
- disconnecting %q error: %w
- ensuring connection: %w
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/3393816b605d0882.
Report an issue: GitHub.