wavetermdev/waveterm · error

server is no longer running, cannot send new requests

Error message

server is no longer running, cannot send new requests

What it means

WshRpc refuses to send new requests once its server has been marked done (IsServerDone). This guards against writing onto a dead/closed connection and fails fast instead of hanging on a response that will never arrive.

Source

Thrown at pkg/wshutil/wshrpc.go:765

func (handler *RpcResponseHandler) Finalize() {
	// Always unregister the handler from the map, even if already done
	if handler.reqId != "" {
		handler.w.unregisterResponseHandler(handler.reqId)
	}
	if handler.done.Load() {
		return
	}
	// SendResponse with done=true will call close() via defer, even when reqId is empty
	handler.SendResponse(nil, true)
}

func (handler *RpcResponseHandler) IsDone() bool {
	return handler.done.Load()
}

func (w *WshRpc) SendComplexRequest(command string, data any, opts *wshrpc.RpcOpts) (rtnHandler *RpcRequestHandler, rtnErr error) {
	if w.IsServerDone() {
		return nil, errors.New("server is no longer running, cannot send new requests")
	}
	if opts == nil {
		opts = &wshrpc.RpcOpts{}
	}
	timeoutMs := opts.Timeout
	if timeoutMs <= 0 {
		timeoutMs = DefaultTimeoutMs
	}
	defer func() {
		panichandler.PanicHandler("SendComplexRequest", recover())
	}()
	if command == "" {
		return nil, fmt.Errorf("command cannot be empty")
	}
	handler := &RpcRequestHandler{
		w:           w,
		ctxCancelFn: &atomic.Pointer[context.CancelFunc]{},
	}

View on GitHub (pinned to a4447c1563)

Solutions

  1. Check w.IsServerDone() (or connection state) before sending; skip or re-establish the connection first.
  2. Recreate the client/connection and retry the request after reconnecting.
  3. Restructure code so all RPCs complete before shutdown, or cancel in-flight work at teardown.
  4. Add a guard in your wrapper that converts this error into a reconnect-and-retry flow.
  5. Avoid holding WshRpc references beyond the owning component's lifetime.

Example fix

// before
resp, err := wshobj.SendComplexRequestTimeOut(ctx, "wave:info", opts, 3000) // panics-style hard error after close
// after
if wshobj.IsServerDone() {
    return fmt.Errorf("connection closed, skipping request")
}
resp, err := wshobj.SendComplexRequestTimeOut(ctx, "wave:info", opts, 3000)
Defensive patterns

Strategy: validation

Validate before calling

if w.IsServerDone() {
    return fmt.Errorf("skipping %s: server closed", command)
}

Try / catch

hdl, err := w.SendComplexRequest(command, data, opts)
if err != nil && strings.Contains(err.Error(), "server is no longer running") {
    w = reconnect(); hdl, err = w.SendComplexRequest(command, data, opts)
}

Prevention

When it happens

Trigger: Calling w.SendComplexRequest (or wrappers like SendRpc/SendComplexRequestTimeOut) after the WshRpc instance's server side has been shut down/closed (done flag set, e.g. connection teardown or process exit).

Common situations: Issuing commands from a goroutine while the terminal/block connection closes; calling wsh clients after app shutdown; long-lived background tasks outliving their connection.

Related errors


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