shadow1ng/fscan · error

expected oracle data packet, got %d

Error message

expected oracle data packet, got %d

What it means

Session.read reads a packet and, once the buffered data is exhausted, requires the next packet to be a DATA packet. RESEND packets are explicitly unsupported and any other type triggers 'expected oracle data packet, got %d'. It indicates the server sent a control packet where the client expected payload data.

Source

Thrown at plugins/services/oracle_raw.go:337

func (s *oracleSession) reset() {
	s.in = nil
	s.out.Reset()
	s.index = 0
	s.summary = nil
}

func (s *oracleSession) read(n int) ([]byte, error) {
	for s.index+n > len(s.in) {
		p, err := s.readPacket()
		if err != nil {
			return nil, err
		}
		if p.typ == oraclePacketResend {
			return nil, errors.New("oracle resend is not supported")
		}
		if p.typ != oraclePacketData {
			return nil, fmt.Errorf("expected oracle data packet, got %d", p.typ)
		}
	}
	ret := s.in[s.index : s.index+n]
	s.index += n
	return ret, nil
}

func (s *oracleSession) putBytes(data ...byte) {
	s.out.Write(data)
}

func (s *oracleSession) putString(v string) {
	s.putClr([]byte(v))
}

func (s *oracleSession) putInt(v interface{}, size uint8, bigEndian, compress bool) {
	num := toInt64(v)
	if compress {

View on GitHub (pinned to 95cc12e753)

Solutions

  1. Re-establish the TNS session from scratch — a mid-stream control packet usually invalidates the session state
  2. If RESEND occurs, the server wants the connect data retransmitted; the lightweight client does not support this, so avoid triggers (unstable network, slow handshake)
  3. Log the actual packet type to identify which control packet the server sent
  4. Check for session desync caused by an earlier read error that was ignored

Example fix

// before
if p.typ == oraclePacketResend {
    return nil, errors.New("oracle resend is not supported")
}
// after
if p.typ == oraclePacketResend {
    return nil, fmt.Errorf("oracle resend requested by server; reconnect required")
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before reading data, verify session state is sane
if s.handshakeComplete == false {
    return errors.New("session not ready for data reads")
}

Type guard

func isDataPacket(p *oraclePacket) bool { return p != nil && p.typ == oraclePacketData }

Try / catch

b, err := s.read(n)
if err != nil {
    if strings.Contains(err.Error(), "expected oracle data packet") {
        // server sent control/resend packet: rebuild the session
        return reestablishSession(ctx)
    }
    return err
}

Prevention

When it happens

Trigger: getByte/getBytes/getInt64/getNullTermString call s.read, the buffer is empty, and the freshly read packet has typ != oraclePacketData (or is a RESEND packet); TestSessionRead covers this.

Common situations: Server requests a resend because it lost handshake state; session desync after an earlier parse error; server rejects the session mid-stream and sends an error/control packet type.

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


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