fatedier/frp · error
create encryption stream error: %v
Error message
create encryption stream error: %v
What it means
wrapVisitorConn failed while turning the raw visitor connection into an encrypted stream via libio.WithEncryption, which initializes an AES cipher by exchanging a salt and derived key over the connection. Failure here is almost always an I/O error writing the initialization data, because AES key derivation itself does not error for arbitrary secrets.
Source
Thrown at client/visitor/visitor.go:209
visitorConn.Close()
return nil, fmt.Errorf("read newVisitorConnRespMsg error: %v", err)
}
_ = visitorConn.SetReadDeadline(time.Time{})
if newVisitorConnRespMsg.Error != "" {
visitorConn.Close()
return nil, fmt.Errorf("start new visitor connection error: %s", newVisitorConnRespMsg.Error)
}
return visitorConn, nil
}
func wrapVisitorConn(conn io.ReadWriteCloser, cfg *v1.VisitorBaseConfig) (io.ReadWriteCloser, func(), error) {
rwc := conn
if cfg.Transport.UseEncryption {
var err error
rwc, err = libio.WithEncryption(rwc, []byte(cfg.SecretKey))
if err != nil {
return nil, func() {}, fmt.Errorf("create encryption stream error: %v", err)
}
}
recycleFn := func() {}
if cfg.Transport.UseCompression {
rwc, recycleFn = libio.WithCompressionFromPool(rwc)
}
return rwc, recycleFn, nil
}
View on GitHub (pinned to 6c8a8d0a97)
Solutions
- Ensure useEncryption matches on both sides: the visitor config and the stcp/xtcp proxy config must both set transport.useEncryption = true.
- Check frps and the serving frpc logs for the peer closing the stream right at handshake time.
- If this appears together with errors 120/121 intermittently, the same flaky network path is the root cause.
- Retry the visitor connection; persistent recurrence points to the encryption flag mismatch.
Defensive patterns
Strategy: validation
Validate before calling
// Ensure both endpoints agree on encryption before dialing
vBase := visitorCfg.GetBaseConfig()
pBase := proxyCfg.GetBaseConfig()
if vBase.Transport.UseEncryption != pBase.Transport.UseEncryption {
return fmt.Errorf("useEncryption mismatch between visitor and proxy")
} Prevention
- Mirror transport.useEncryption and useCompression between the stcp/xtcp proxy and its visitors
- Template visitor configs from the proxy config so flags stay in sync
When it happens
Trigger: libio.WithEncryption(rwc, []byte(cfg.SecretKey)) returns an error when writing the key-exchange preamble to the just-established connection fails; the peer closed between NewVisitorConnResp and this step.
Common situations: Server dropped the connection immediately after a successful visitor handshake; TLS/middlebox truncating the stream; transport.useEncryption enabled on the visitor while the target proxy owner has it disabled, so the peer closes on unexpected ciphertext framing.
Related errors
- visitor plugin type is empty
- name is required
- server name is required
- bind port is required
- destinationIP is required
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/6b7d7d3bcac5023f.
Report an issue: GitHub.