shadow1ng/fscan · error

unexpected query opcode: %d

Error message

unexpected query opcode: %d

What it means

Guard in validateCQLQueryResponse: a post-auth QUERY exchange returned an opcode that is neither cqlOpResult nor cqlOpError. It fires when the Cassandra peer violates the expected RESULT/ERROR reply contract, so the query response cannot be validated.

Source

Thrown at plugins/services/cassandra.go:220

	if bodyLen == 0 {
		return opcode, []byte{}, nil
	}
	if bodyLen > maxCQLFrameBody {
		return opcode, nil, fmt.Errorf("cassandra frame too large: %d", bodyLen)
	}
	body := make([]byte, bodyLen)
	if _, err := io.ReadFull(conn, body); err != nil {
		return opcode, nil, err
	}
	return opcode, body, nil
}

func validateCQLQueryResponse(opcode byte, body []byte) error {
	if opcode == cqlOpError {
		return fmt.Errorf("cassandra query failed: %s", string(body))
	}
	if opcode != cqlOpResult {
		return fmt.Errorf("unexpected query opcode: %d", opcode)
	}
	return nil
}

// cqlStringMap CQL string map 编码: [2B count] [pairs: [2B len] [str]]
func cqlStringMap(m map[string]string) []byte {
	var buf []byte
	buf = append(buf, 0x00, byte(len(m))) // count as short
	for k, v := range m {
		buf = append(buf, cqlShortString(k)...)
		buf = append(buf, cqlShortString(v)...)
	}
	return buf
}

func cqlShortString(s string) []byte {
	b := []byte(s)
	buf := make([]byte, 2+len(b))

View on GitHub (pinned to 95cc12e753)

Solutions

  1. Log the opcode value and compare against the CQL native protocol opcode table to identify the mismatch.
  2. Ensure the auth-phase frames were fully consumed before sending the test query (no leftover bytes in the stream).
  3. Pin a supported protocol version and reconnect to resynchronize framing.
Defensive patterns

Strategy: retry

Try / catch

if err := validateCQLQueryResponse(opcode, body); err != nil && strings.HasPrefix(err.Error(), "unexpected query opcode") {
    return reconnectAndRetry() // framing may be desynced
}

Prevention

When it happens

Trigger: validateCQLQueryResponse is called with an opcode that is neither cqlOpError nor cqlOpResult — e.g. the connection returned an AUTHENTICATE or SUPPORTS frame, or framing desynced so the opcode byte is garbage.

Common situations: Talking to an intermediary or non-Cassandra server mid-stream; protocol-version mismatch corrupting frame boundaries; reading a stale response left over from the auth phase.

Related errors


AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06). Data as JSON: /api/errors/de24a08696e2876f. Report an issue: GitHub.