rathole-org/rathole · error
Expect TCP traffic. Please check the configuration.
Error message
Expect TCP traffic. Please check the configuration.
What it means
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.
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
Example fix
// before (client.toml) [client.services.dns] local_addr = "127.0.0.1:53" # inferred udp // after [client.services.dns] local_addr = "127.0.0.1:53" type = "tcp" # match the server's service type
Defensive patterns
Strategy: validation
Validate before calling
// Confirm the local service listens on TCP before declaring it as a tcp service:
import socket
s = socket.socket(); s.settimeout(2)
try:
s.connect(('127.0.0.1', 22)); print('TCP OK')
except OSError as e:
print('Not a TCP service:', e)
finally:
s.close() Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- Expect UDP traffic. Please check the configuration.
- Cannot determine running as a server or a client
- The token of service
- The feature ' ' is not compiled in this binary. Please…
- Neither of the feature
AI-assisted analysis of rathole-org/rathole@a292f7ed54 (2026-09-07).
Data as JSON: /api/errors/3257b423dd235024.
Report an issue: GitHub.
Appendix: source
Thrown at src/client.rs:222
// Send nonce
let v: &[u8; HASH_WIDTH_IN_BYTES] = args.session_key[..].try_into().unwrap();
let hello = Hello::DataChannelHello(CURRENT_PROTO_VERSION, v.to_owned());
conn.write_all(&bincode::serialize(&hello).unwrap()).await?;
conn.flush().await?;
Ok(conn)
}
async fn run_data_channel<T: Transport>(args: Arc<RunDataChannelArgs<T>>) -> Result<()> {
// Do the handshake
let mut conn = do_data_channel_handshake(args.clone()).await?;
// Forward
match read_data_cmd(&mut conn).await? {
DataChannelCmd::StartForwardTcp => {
if args.service.service_type != ServiceType::Tcp {
bail!("Expect TCP traffic. Please check the configuration.")
}
run_data_channel_for_tcp::<T>(conn, &args.service.local_addr).await?;
}
DataChannelCmd::StartForwardUdp => {
if args.service.service_type != ServiceType::Udp {
bail!("Expect UDP traffic. Please check the configuration.")
}
run_data_channel_for_udp::<T>(conn, &args.service.local_addr, args.service.prefer_ipv6).await?;
}
}
Ok(())
}
// Simply copying back and forth for TCP
#[instrument(skip(conn))]
async fn run_data_channel_for_tcp<T: Transport>(
mut conn: T::Stream,
local_addr: &str,View on GitHub (pinned to a292f7ed54)