wavetermdev/waveterm · error

non-command request packets may not have timeout set

Error message

non-command request packets may not have timeout set

What it means

Timeout (deadline negotiation) is specified only on the initial command packet of an RPC. Follow-up request packets (ReqId without Command) may not set Timeout; Validate rejects it to avoid ambiguous deadline resets.

Source

Thrown at pkg/wshutil/wshrpc.go:178

	}
	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")
		}
		return nil
	}
	if r.ReqId != "" {
		if r.ResId == "" {
			return fmt.Errorf("request packets must have resid set")
		}
		if r.Timeout != 0 {
			return fmt.Errorf("non-command request packets may not have timeout set")
		}
		return nil
	}
	if r.ResId != "" {
		if r.Command != "" {
			return fmt.Errorf("response packets may not have command set")
		}
		if r.ReqId == "" {
			return fmt.Errorf("response packets must have reqid set")
		}
		if r.Timeout != 0 {
			return fmt.Errorf("response packets may not have timeout set")
		}
		return nil
	}
	return fmt.Errorf("invalid packet: must have command, reqid, or resid set")
}

View on GitHub (pinned to a4447c1563)

Solutions

  1. Set Timeout to 0 on follow-up request packets
  2. Implement per-call timeout changes by canceling and re-issuing a new command with a new ReqId
  3. When cloning the original message for continuations, strip Timeout explicitly

Example fix

// before
msg := wshutil.RpcMessage{ReqId: reqId, ResId: resId, Timeout: origTimeout}
// after
msg := wshutil.RpcMessage{ReqId: reqId, ResId: resId, Timeout: 0}
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

func followUpHasNoTimeout(msg wshutil.RpcMessage) bool {
	return msg.Command != "" || msg.Timeout == 0
}

Try / catch

if err := msg.Validate(); err != nil {
	return fmt.Errorf("follow-up request has timeout: %w", err)
}

Prevention

When it happens

Trigger: Calling Validate on an RpcMessage with ReqId set, ResId set, Command empty, and Timeout != 0.

Common situations: A helper that copies all fields of the original command into continuation packets, carrying Timeout along; retries implemented by re-sending with a fresh Timeout on the same ReqId.

Understand the failure class

Related errors


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