shadow1ng/fscan · error

unexpected query opcode

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.

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.

Appendix: 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)