wavetermdev/waveterm · error
timeout sending request
Error message
timeout sending request
What it means
SendComplexRequest registers the request handler and then writes the request bytes to OutputCh; if the handler's context is done before the write is accepted, registration is finalized and this error is returned — the request never made it onto the wire.
Source
Thrown at pkg/wshutil/wshrpc.go:807
}
req := &RpcMessage{
Command: command,
ReqId: handler.reqId,
Data: data,
Timeout: timeoutMs,
Route: opts.Route,
}
barr, err := json.Marshal(req)
if err != nil {
return nil, err
}
handler.respCh = w.registerRpc(handler, command, opts.Route, handler.reqId)
select {
case w.OutputCh <- barr:
return handler, nil
case <-handler.ctx.Done():
handler.finalize()
return nil, fmt.Errorf("timeout sending request")
}
}
func (w *WshRpc) IsServerDone() bool {
w.Lock.Lock()
defer w.Lock.Unlock()
return w.ServerDone
}
func (w *WshRpc) setServerDone() {
w.Lock.Lock()
defer w.Lock.Unlock()
w.ServerDone = true
close(w.CtxDoneCh)
utilfn.DrainChannelSafe(w.InputCh, "wshrpc.setServerDone")
}
func (w *WshRpc) retrySendTimeout(resId string) {View on GitHub (pinned to a4447c1563)
Solutions
- Check ctx.Err() before sending and avoid issuing requests with cancelled/expired contexts.
- Increase the timeout via RpcOpts (TimeoutMs) if the output channel can be slow.
- Ensure the connection read loop keeps running and draining OutputCh during the request.
- Retry the request on a fresh, live connection/context after verifying the peer is up.
Example fix
// before
ctx, cancel := context.WithTimeout(ctx, 50*time.Millisecond)
resp, err := w.SendComplexRequest("waveclient:get", args, &wshutil.RpcOpts{Route: route})
// after
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
resp, err := w.SendComplexRequest("waveclient:get", args, &wshutil.RpcOpts{Route: route, TimeoutMs: 5000}) Defensive patterns
Strategy: try-catch
Validate before calling
if ctx.Err() != nil {
return fmt.Errorf("cannot send request: context already done: %w", ctx.Err())
} Try / catch
handler, err := w.SendComplexRequest(cmd, args, opts)
if err != nil && strings.Contains(err.Error(), "timeout sending request") {
// output channel blocked or ctx expired; check connection health, then retry with a longer timeout
return retryWithBackoff(func() error { _, err := w.SendComplexRequest(cmd, args, opts); return err })
} Prevention
- Never pass already-cancelled contexts into request calls.
- Use realistic TimeoutMs values for your workload.
- Ensure the connection read loop stays alive to drain OutputCh.
- Retry idempotent requests with backoff after connection recovery.
When it happens
Trigger: Calling a request with a context that is already cancelled/expired; connection shutdown closing OutputCh/consumer while the request is being sent; per-request deadline shorter than the time needed to enqueue the packet.
Common situations: Firing RPCs during teardown of a block/connection; callers passing an already-cancelled context; timeouts configured too aggressively (or DefaultTimeoutMs too small for a congested output channel).
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/ca54bb20eb9d01f9.
Report an issue: GitHub.