txthinking/brook · error

cannot create exchanger from

Error message

cannot create exchanger from 

What it means

CreateExchanger dispatches on the brook link's Kind to build a client/server exchanger pair. If the kind does not match any supported scheme (ws, wss, quic, etc.), it returns this error with the unrecognized kind appended. It means the link string's scheme prefix is not a protocol this build supports.

Source

Thrown at brooklink.go:276

		}
		rc, err := QUICDialUDP(src, socks5.ToAddress(dstb[0], dstb[1:len(dstb)-2], dstb[len(dstb)-2:]), blk.Address, blk.Tc, udptimeout)
		if err != nil {
			return nil, nil, err
		}
		var sc Exchanger
		if blk.V.Get("withoutBrookProtocol") != "true" {
			sc, err = NewPacketClient(blk.Password, src, rc, udptimeout, dstb)
		}
		if blk.V.Get("withoutBrookProtocol") == "true" {
			sc, err = NewSimplePacketClient(blk.Password, src, rc, udptimeout, dstb)
		}
		if err != nil {
			rc.Close()
			return nil, nil, err
		}
		return sc, rc, nil
	}
	return nil, nil, errors.New("cannot create exchanger from " + blk.Kind)
}

func (x *BrookLink) PrepareSocks5Server(addr, ip string, tcptimeout, udptimeout int) error {
	if err := limits.Raise(); err != nil {
		Log(Error{"when": "try to raise system limits", "warning": err.Error()})
	}
	if x.Kind == "quicserver" {
		if runtime.GOOS == "linux" {
			c := exec.Command("sysctl", "-w", "net.core.rmem_max=2500000")
			b, err := c.CombinedOutput()
			if err != nil {
				Log(Error{"when": "try to raise UDP Receive Buffer Size", "warning": string(b)})
			}
		}
		if runtime.GOOS == "darwin" {
			c := exec.Command("sysctl", "-w", "kern.ipc.maxsockbuf=3014656")
			b, err := c.CombinedOutput()
			if err != nil {

View on GitHub (pinned to 5cd13ef3b1)

Solutions

  1. Print/inspect blk.Kind and correct the scheme in the link string to a supported one (ws, wss, quic, etc.)
  2. Regenerate the link with a matching brook version so the scheme is recognized
  3. Upgrade the library if the link uses a newer protocol kind your build doesn't support
  4. If Kind is empty, check that the link URL was parsed correctly and has a scheme prefix

Example fix

// before
blk, _ := NewBrookLink("ws4ss://server:443?something")
ex := CreateExchanger(blk)
// after
blk, _ := NewBrookLink("wss://server:443?withoutHeader=true")
ex := CreateExchanger(blk)
Defensive patterns

Strategy: validation

Validate before calling

supported := map[string]bool{"ws": true, "wss": true, "quic": true /* per your build */}
if !supported[blk.Kind] {
	return fmt.Errorf("unsupported brook kind: %q", blk.Kind)
}

Try / catch

sc, rc, err := CreateExchanger(blk)
if err != nil {
	if strings.HasPrefix(err.Error(), "cannot create exchanger from") {
		log.Printf("unknown brook kind %q — check link scheme", blk.Kind)
	}
	return err
}

Prevention

When it happens

Trigger: Calling CreateExchanger (directly or via TCPHandle/UDPHandle) with a BrookLink whose Kind string is unknown — e.g. a typo'd or unsupported scheme like 'ws4ss://', an empty scheme, or a scheme added in a newer brook version.

Common situations: Hand-crafted brook:// link strings with wrong scheme; links generated by newer brook clients passed to an older library; empty/malformed link URL where scheme parsing yields "" (note the double space in the message when Kind is empty).

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 txthinking/brook@5cd13ef3b1 (2026-09-06). Data as JSON: /api/errors/5811f92157e7e1f6. Report an issue: GitHub.