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

  1. Inspect the caller building the command — ensure it starts with '$' and is non-empty
  2. Verify outbuf is populated (Fprintf to outbuf) before exec/send
  3. 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

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


AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31). Data as JSON: /api/errors/2ed05c5113d1b8ce. Report an issue: GitHub.