wavetermdev/waveterm · error

cancel packets may not have command set

Error message

cancel packets may not have command set

What it means

Packet validation error: CANCEL packets must not carry a command. Cancelling identifies the target solely by resid; setting command on a cancel packet violates the wire protocol and the packet is rejected.

Source

Thrown at pkg/wshutil/wshrpc.go:151

	Source   string `json:"source,omitempty"` // source route id
	Cont     bool   `json:"cont,omitempty"`   // flag if additional requests/responses are forthcoming
	Cancel   bool   `json:"cancel,omitempty"` // used to cancel a streaming request or response (sent from the side that is not streaming)
	Error    string `json:"error,omitempty"`
	DataType string `json:"datatype,omitempty"`
	Data     any    `json:"data,omitempty"`
}

func (r *RpcMessage) IsRpcRequest() bool {
	return r.Command != "" || r.ReqId != ""
}

func (r *RpcMessage) Validate() error {
	if r.ReqId != "" && r.ResId != "" {
		return fmt.Errorf("request packets may not have both reqid and resid set")
	}
	if r.Cancel {
		if r.Command != "" {
			return fmt.Errorf("cancel packets may not have command set")
		}
		if r.ReqId == "" && r.ResId == "" {
			return fmt.Errorf("cancel packets must have reqid or resid set")
		}
		if r.Data != nil {
			return fmt.Errorf("cancel packets may not have data set")
		}
		return nil
	}
	if r.Command != "" {
		if r.ResId != "" {
			return fmt.Errorf("command packets may not have resid set")
		}
		if r.Error != "" {
			return fmt.Errorf("command packets may not have error set")
		}
		if r.DataType != "" {
			return fmt.Errorf("command packets may not have datatype set")

View on GitHub (pinned to a4447c1563)

Solutions

  1. Remove the Command field when canceling (send only Cancel + the target ReqId/ResId)
  2. Construct the cancel message fresh: RpcMessage{Cancel: true, ReqId: originalReqId}
  3. Check code paths that set Cancel=true so they do not leave Command populated

Example fix

// before
msg := wshutil.RpcMessage{Cancel: true, Command: "controller.sendinput", ReqId: origId}
// after
msg := wshutil.RpcMessage{Cancel: true, ReqId: origId}
Defensive patterns

Strategy: validation

Validate before calling

if msg.Cancel && msg.Command != "" {
	msg.Command = ""
}
if err := msg.Validate(); err != nil { return err }

Type guard

func isWellFormedCancel(msg wshutil.RpcMessage) bool {
	return !msg.Cancel || (msg.Command == "" && (msg.ReqId != "" || msg.ResId != "") && msg.Data == nil)
}

Try / catch

if err := msg.Validate(); err != nil {
	return fmt.Errorf("invalid cancel packet: %w", err)
}

Prevention

When it happens

Trigger: Calling Validate on an RpcMessage with Cancel=true and Command set to a non-empty string.

Common situations: A caller builds a normal command message then flips Cancel=true to cancel it instead of clearing the command; generic message-mutation helpers that toggle Cancel without scrubbing other fields.

Related errors


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