{"record":{"id":"3257b423dd235024","repo":"rathole-org/rathole","slug":"expect-tcp-traffic-please-check-the-configuration","errorCode":null,"errorMessage":"Expect TCP traffic. Please check the configuration.","messagePattern":"Expect TCP traffic\\. Please check the configuration\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/client.rs","lineNumber":222,"sourceCode":"\n    // Send nonce\n    let v: &[u8; HASH_WIDTH_IN_BYTES] = args.session_key[..].try_into().unwrap();\n    let hello = Hello::DataChannelHello(CURRENT_PROTO_VERSION, v.to_owned());\n    conn.write_all(&bincode::serialize(&hello).unwrap()).await?;\n    conn.flush().await?;\n\n    Ok(conn)\n}\n\nasync fn run_data_channel<T: Transport>(args: Arc<RunDataChannelArgs<T>>) -> Result<()> {\n    // Do the handshake\n    let mut conn = do_data_channel_handshake(args.clone()).await?;\n\n    // Forward\n    match read_data_cmd(&mut conn).await? {\n        DataChannelCmd::StartForwardTcp => {\n            if args.service.service_type != ServiceType::Tcp {\n                bail!(\"Expect TCP traffic. Please check the configuration.\")\n            }\n            run_data_channel_for_tcp::<T>(conn, &args.service.local_addr).await?;\n        }\n        DataChannelCmd::StartForwardUdp => {\n            if args.service.service_type != ServiceType::Udp {\n                bail!(\"Expect UDP traffic. Please check the configuration.\")\n            }\n            run_data_channel_for_udp::<T>(conn, &args.service.local_addr, args.service.prefer_ipv6).await?;\n        }\n    }\n    Ok(())\n}\n\n// Simply copying back and forth for TCP\n#[instrument(skip(conn))]\nasync fn run_data_channel_for_tcp<T: Transport>(\n    mut conn: T::Stream,\n    local_addr: &str,","sourceCodeStart":204,"sourceCodeEnd":240,"githubUrl":"https://github.com/rathole-org/rathole/blob/a292f7ed5402f840415fc6a53827da2f34337856/src/client.rs#L204-L240","documentation":"The client's data channel completed the handshake and received a StartForwardTcp command from the server, but the local service configured for this channel is not of type TCP. run_data_channel bails out because forwarding TCP traffic to a non-TCP local service would be wrong. This indicates a mismatch between the client's and server's service type configuration.","triggerScenarios":"Server sends DataChannelCmd::StartForwardTcp while the client's service entry has service_type != ServiceType::Tcp (i.e. it is UDP), detected in run_data_channel after do_data_channel_handshake.","commonSituations":"The same service name is declared as UDP on the client but TCP on the server; copy-pasting a config where the remote side exposes a TCP port but the local service (e.g. a DNS or game server) is UDP.","solutions":["Make the service type consistent: set the service to TCP on both client and server configs (or use udp on both)","Check that the local_addr actually speaks TCP before declaring it a TCP service","Restart both ends after fixing the config so the control channel re-negotiates"],"exampleFix":"// before (client.toml)\n[client.services.dns]\nlocal_addr = \"127.0.0.1:53\"   # inferred udp\n\n// after\n[client.services.dns]\nlocal_addr = \"127.0.0.1:53\"\ntype = \"tcp\"                   # match the server's service type","handlingStrategy":"validation","validationCode":"// Confirm the local service listens on TCP before declaring it as a tcp service:\nimport socket\ns = socket.socket(); s.settimeout(2)\ntry:\n    s.connect(('127.0.0.1', 22)); print('TCP OK')\nexcept OSError as e:\n    print('Not a TCP service:', e)\nfinally:\n    s.close()","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep the type field for each service identical in both client and server configs","Remember well-known services: SSH/HTTP are TCP, DNS/QUIC/games are often UDP","Diff client and server service definitions after any config change"],"tags":["rust","configuration","tcp","service-type-mismatch"],"backgroundTag":"invalid-config-value","analyzedSha":"a292f7ed5402f840415fc6a53827da2f34337856","analyzedAt":"2026-09-07T09:56:55.739Z","contentChangedAt":"2026-09-07T09:56:55.739Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}