{"record":{"id":"56207b507cff796c","repo":"fatedier/frp","slug":"create-control-crypto-read-writer-w","errorCode":null,"errorMessage":"create control crypto read writer: %w","messagePattern":"create control crypto read writer: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"client/control_session.go","lineNumber":90,"sourceCode":"\tloginMsg, err := d.buildLoginMsg(previousRunID)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tloginResult, err := d.exchangeLogin(conn, loginMsg)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tloginRespMsg := loginResult.resp\n\tif loginRespMsg.Error != \"\" {\n\t\treturn nil, errors.New(loginRespMsg.Error)\n\t}\n\n\tvar controlRW io.ReadWriter = conn\n\tif d.clientSpec == nil || d.clientSpec.Type != \"ssh-tunnel\" {\n\t\tcontrolRW, err = d.newControlReadWriter(conn, loginResult.crypto)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"create control crypto read writer: %w\", err)\n\t\t}\n\t}\n\n\tsuccess = true\n\treturn &SessionContext{\n\t\tCommon:         d.common,\n\t\tRunID:          loginRespMsg.RunID,\n\t\tConn:           msg.NewConn(conn, msg.NewReadWriter(controlRW, d.common.Transport.WireProtocol)),\n\t\tAuth:           d.auth,\n\t\tConnector:      newMessageConnector(connector, d.common.Transport.WireProtocol),\n\t\tVnetController: d.vnetController,\n\t\tUDPPacketCodec: loginResult.udpPacketCodec,\n\t}, nil\n}\n\nfunc (d *controlSessionDialer) buildLoginMsg(previousRunID string) (*msg.Login, error) {\n\thostname, _ := os.Hostname()\n\tloginMsg := &msg.Login{","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/fatedier/frp/blob/6c8a8d0a97d03b44e9528d30b30c70cb9d61b405/client/control_session.go#L72-L108","documentation":"During the frpc-frps control connection login, after authentication succeeds the client upgrades the raw TCP conn to an encrypted read/writer via newControlReadWriter using the negotiated crypto context. This error wraps any failure of that crypto setup, whose real causes live in pkg/proto/wire: un-JSON-able hello transcripts, an unknown AEAD algorithm selected by the server, an algorithm the client never advertised, or a wrong-length server random.","triggerScenarios":"Login to a server whose ServerHello selects a crypto algorithm the client did not offer, or that sends malformed hello payloads; effectively only with a mismatched/modified frps build or a man-in-the-middle altering the handshake. Skipped entirely for ssh-tunnel client spec connections.","commonSituations":"frpc and frps built from different forks/versions with divergent crypto negotiation; a transparent proxy (corporate firewall, TLS-terminating LB) corrupting the binary handshake; extremely rare protocol-level incompatibility after a downgrade.","solutions":["Run matching frpc and frps versions (same release)","Ensure nothing between client and server terminates or rewrites the control connection (no TLS-offloading proxies on the frps port)","Capture the wrapped cause — 'unknown selected crypto algorithm' vs 'decode ... transcript' points to server build vs payload corruption","Retry on a clean network path to rule out middlebox interference"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"_, err := svc.Login(ctx)\nif err != nil && strings.Contains(err.Error(), \"create control crypto read writer\") {\n\t// protocol/crypto mismatch with server: check version parity and network path\n}","preventionTips":["Deploy frpc and frps from the same release","Keep the control connection free of TLS-offloading middleboxes","Log the wrapped cause — it distinguishes build mismatch from payload corruption"],"tags":["frp","frpc","crypto","handshake","network"],"backgroundTag":null,"analyzedSha":"6c8a8d0a97d03b44e9528d30b30c70cb9d61b405","analyzedAt":"2026-08-15T06:53:27.215Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}