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
- Set Timeout to 0 on follow-up request packets
- Implement per-call timeout changes by canceling and re-issuing a new command with a new ReqId
- 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
- Only set Timeout on the initial command packet
- When cloning messages for continuations, strip Timeout and Command
- Use cancel + re-issue for changing deadlines instead of re-sending with a new Timeout
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
- 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)
- getting file info: %w
- unable to obtain remote info from connserver: %w
- unable to obtain client info: %w
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/eadb9d956f35686b.
Report an issue: GitHub.