wavetermdev/waveterm · warning

timeout sending cancel

Error message

timeout sending cancel

What it means

SendCancelResponse writes a cancel acknowledgment to the RPC output channel; if the surrounding context is done before the write is accepted, the handler is finalized and this error is returned. It indicates the cancel notification itself could not be delivered in time.

Source

Thrown at pkg/wshutil/wshrpc.go:573

	return handler.ctx
}

func (handler *RpcRequestHandler) SendCancel(ctx context.Context) error {
	defer func() {
		panichandler.PanicHandler("SendCancel", recover())
	}()
	msg := &RpcMessage{
		Cancel: true,
		ReqId:  handler.reqId,
	}
	barr, _ := json.Marshal(msg) // will never fail
	select {
	case handler.w.OutputCh <- barr:
		handler.finalize()
		return nil
	case <-ctx.Done():
		handler.finalize()
		return fmt.Errorf("timeout sending cancel")
	}
}

func (handler *RpcRequestHandler) ResponseDone() bool {
	if handler.cachedResp != nil {
		return false
	}
	select {
	case msg, more := <-handler.respCh:
		if !more {
			return true
		}
		handler.cachedResp = msg
		return false
	default:
		return false
	}
}

View on GitHub (pinned to a4447c1563)

Solutions

  1. Check ctx.Err() before calling SendCancelResponse; skip the cancel send if the context is already done.
  2. Ensure the connection reader keeps draining OutputCh so the cancel message can be written.
  3. Treat this error as benign during shutdown (the handler was finalized either way) and log at debug level instead of retrying.

Example fix

// before
err := handler.SendCancelResponse(ctx)
// after
if ctx.Err() == nil {
    err := handler.SendCancelResponse(ctx)
}
Defensive patterns

Strategy: try-catch

Validate before calling

if ctx.Err() != nil {
    return nil // cancel notification cannot be delivered
}

Try / catch

if err := handler.SendCancelResponse(ctx); err != nil && strings.Contains(err.Error(), "timeout sending cancel") {
    // context already done; handler finalized — safe to ignore/log at debug level
}

Prevention

When it happens

Trigger: Calling SendCancelResponse after the request context was already cancelled/expired; OutputCh backpressure (downstream not consuming) combined with a closing/shut-down context.

Common situations: Cancelling a request while the connection is being torn down; caller cancels with an already-expired deadline; slow consumer blocking OutputCh during shutdown.

Understand the failure class

Related errors


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/fe1bd9eeb7f09977. Report an issue: GitHub.