shadow1ng/fscan · error

Unknown FastPathPDU type 0x%x

Error message

Unknown FastPathPDU type 0x%x

What it means

The default branch of the fast-path update switch in pdu/data.go fires when the update code from the server is not any known FASTPATH_UPDATETYPE_* value. The library logs a debug line and returns 'Unknown FastPathPDU type 0x%x' because the PDU cannot be classified or decoded.

Source

Thrown at libs/grdp/protocol/pdu/data.go:930

		// 绘图指令,认证检测不需要处理
		return nil, errors.New(fmt.Sprintf("Unsupport FastPathPDU type 0x%x", code))
	case FASTPATH_UPDATETYPE_BITMAP:
		d = &FastPathBitmapUpdateDataPDU{}
	case FASTPATH_UPDATETYPE_PALETTE:
	case FASTPATH_UPDATETYPE_SYNCHRONIZE:
	case FASTPATH_UPDATETYPE_SURFCMDS:
		//d = &FastPathSurfaceCmds{}
	case FASTPATH_UPDATETYPE_PTR_NULL:
	case FASTPATH_UPDATETYPE_PTR_DEFAULT:
	case FASTPATH_UPDATETYPE_PTR_POSITION:
	case FASTPATH_UPDATETYPE_COLOR:
		//d = &FastPathColorPdu{}
	case FASTPATH_UPDATETYPE_CACHED:
	case FASTPATH_UPDATETYPE_POINTER:
	case FASTPATH_UPDATETYPE_LARGE_POINTER:
	default:
		glog.Debugf("Unknown FastPathPDU type 0x%x", code)
		return f, errors.New(fmt.Sprintf("Unknown FastPathPDU type 0x%x", code))
	}
	if d != nil {
		err = d.Unpack(r)
		if err != nil {
			//glog.Error("Unpack:", err)
			return nil, err
		}
	} else {
		return nil, errors.New(fmt.Sprintf("Unsupport FastPathPDU type 0x%x", code))
	}

	f.Data = d
	return f, nil
}

type ShareControlHeader struct {
	TotalLength uint16 `struc:"little"`
	PDUType     uint16 `struc:"little"`

View on GitHub (pinned to 95cc12e753)

Solutions

  1. Update the grdp library to a version supporting the newer FastPath update types.
  2. Log/inspect the code value in the debug output to identify what the server is sending, then add a case for that constant in parseFastPathUpdate.
  3. Verify the stream is not desynchronized: check that preceding PDU parsing consumed exactly the right number of bytes.
  4. If the type is benign for your use case, change the default branch to skip instead of erroring.

Example fix

// before (data.go ~930)
default:
    glog.Debugf("Unknown FastPathPDU type 0x%x", code)
    return f, errors.New(fmt.Sprintf("Unknown FastPathPDU type 0x%x", code))
// after
default:
    glog.Warnf("skipping unknown FastPathPDU type 0x%x", code)
    return f, nil
Defensive patterns

Strategy: try-catch

Try / catch

client.On("error", func(err error) {
    if strings.Contains(err.Error(), "Unknown FastPathPDU type") {
        glog.Warn("unknown fast-path update from server: ", err)
        return
    }
    glog.Error("rdp error: ", err)
})

Prevention

When it happens

Trigger: Receiving a fast-path update PDU whose type byte falls outside the implemented set (ORDERS, BITMAP, PALETTE, SYNCHRONIZE, SURFCMDS, CACHED, POINTER, LARGE_POINTER) — e.g. a reserved/future update type or corrupted stream bytes misaligned so the type nibble is wrong.

Common situations: Connecting to a newer Windows/terminal server using an update type this grdp version doesn't know; stream desynchronization from an earlier parse bug making garbage bytes look like an update header; testing against non-MS RDP servers with proprietary update codes.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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