go-delve/delve · error
gdb protocol error: command doesn't start with '$'
Error message
gdb protocol error: command doesn't start with '$'
What it means
send() is the low-level gdbserial packet transmitter; every GDB remote command must begin with '$' and end with '#' plus a two-hex-digit checksum. The panic guards against corrupt or empty command buffers reaching the wire.
Source
Thrown at pkg/proc/gdbserial/gdbserver_conn.go:1333
return mri, nil
}
// exec executes a message to the stub and reads a response.
// The details of the wire protocol are described here:
//
// https://sourceware.org/gdb/onlinedocs/gdb/Overview.html#Overview
func (conn *gdbConn) exec(cmd []byte, context string) ([]byte, error) {
if err := conn.send(cmd); err != nil {
return nil, err
}
return conn.recv(cmd, context, false)
}
const hexdigit = "0123456789abcdef"
func (conn *gdbConn) send(cmd []byte) error {
if len(cmd) == 0 || cmd[0] != '$' {
panic("gdb protocol error: command doesn't start with '$'")
}
// append checksum to packet
cmd = append(cmd, '#')
sum := checksum(cmd)
cmd = append(cmd, hexdigit[sum>>4], hexdigit[sum&0xf])
attempt := 0
for {
if logflags.GdbWire() {
if len(cmd) > gdbWireMaxLen {
conn.log.Debugf("<- %s...", string(cmd[:gdbWireMaxLen]))
} else {
conn.log.Debugf("<- %s", string(cmd))
}
}
_, err := conn.conn.Write(cmd)
if err != nil {View on GitHub (pinned to a23773e6c3)
Solutions
- Inspect the caller building the command — ensure it starts with '$' and is non-empty
- Verify outbuf is populated (Fprintf to outbuf) before exec/send
- Use unmodified delve; if triggered during normal debugging, capture the packet log and report upstream
Example fix
// before
conn.send(rawBytes) // rawBytes may be empty
// after
if len(rawBytes) == 0 || rawBytes[0] != '$' {
return errors.New("malformed gdb packet")
}
conn.send(rawBytes) Defensive patterns
Strategy: validation
Validate before calling
if len(cmd) == 0 || cmd[0] != '$' {
return errors.New("malformed gdb packet: must start with $")
} Try / catch
defer func() {
if r := recover(); r != nil { err = fmt.Errorf("send: %v", r) }
}() Prevention
- Always build packets via the provided helpers (exec/Fprintf into outbuf)
- Never cache/reuse partially written buffers without Reset+rebuild
- Log outgoing packets in tests to catch malformed construction early
When it happens
Trigger: Any code path that builds a command into conn.outbuf incorrectly (e.g. calling send with an empty buffer, or a buffer whose first byte was overwritten/reset improperly) then calls conn.send(cmd).
Common situations: Forks or patches of delve that construct raw packets; a failed/interleaved outbuf.Reset() leaving an empty buffer; hand-written protocol experiments against the gdbserial package.
Related errors
- selectThread when thread suffix is supported
- not implemented
- threadUpdater: Add after Finish
- unsupported operating system attempting to find Goroutine on
- must specify at least one argument for qRRCmd
AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31).
Data as JSON: /api/errors/2ed05c5113d1b8ce.
Report an issue: GitHub.