ekzhang/bore · error
unexpected initial non-hello message
Error message
unexpected initial non-hello message
What it means
In `Client::new`, the first server message after the handshake was neither `Hello`, `Error`, nor `Challenge` — an unexpected message variant arrived where the protocol requires `Hello(remote_port)`. This indicates the remote endpoint is not speaking the expected bore protocol or the stream is desynchronized.
Solutions
- Verify the target host:port actually runs a bore server (`bore server`).
- Check for proxies/load balancers that might answer before the bore server does.
- Ensure client and server use compatible bore versions.
- Confirm you are not connecting to the HTTP control port of another service.
Example fix
// before (wrong port: HTTP service) bore local 3000 --to example.com --port 80 // after (port where bore server listens) bore local 3000 --to example.com --port 2200
Defensive patterns
Strategy: validation
Validate before calling
// Sanity-check the endpoint before connecting
assert!(!to_host.contains("http"), "use a TCP host:port, not a URL");
// Verify a bore server is listening on that port before Client::new Try / catch
match Client::new(...).await {
Err(e) if e.to_string().contains("unexpected initial non-hello message") => {
eprintln!("target is not a compatible bore server; check host/port/version");
std::process::exit(2);
}
other => other,
} Prevention
- Record the bore server's port in config rather than guessing.
- Test the endpoint with a known-good bore client after server upgrades.
- Bypass or correctly configure TCP proxies in front of the bore server.
When it happens
Trigger: Connecting to a port not actually served by a compatible bore server; a proxy returning an HTTP banner or other protocol data; a mismatched protocol version re-framing messages incorrectly.
Common situations: Wrong port forwarded to a non-bore service; a reverse proxy or load balancer intercepting the TCP connection; client and server versions with incompatible message enums; connecting to an HTTP endpoint by mistake.
Understand the failure class
Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.
Related errors
- server requires secret, but no secret was provided
- expected authentication challenge, but no secret was…
- server error
- server requires authentication, but no client secret was…
- unexpected EOF
AI-assisted analysis of ekzhang/bore@00a735a899 (2026-09-08).
Data as JSON: /api/errors/58ea5bee824e62d4.
Report an issue: GitHub.
Appendix: source
Thrown at src/client.rs:56
local_port: u16,
to: &str,
port: u16,
secret: Option<&str>,
) -> Result<Self> {
let mut stream = Delimited::new(connect_with_timeout(to, CONTROL_PORT).await?);
let auth = secret.map(Authenticator::new);
if let Some(auth) = &auth {
auth.client_handshake(&mut stream).await?;
}
stream.send(ClientMessage::Hello(port)).await?;
let remote_port = match stream.recv_timeout().await? {
Some(ServerMessage::Hello(remote_port)) => remote_port,
Some(ServerMessage::Error(message)) => bail!("server error: {message}"),
Some(ServerMessage::Challenge(_)) => {
bail!("server requires authentication, but no client secret was provided");
}
Some(_) => bail!("unexpected initial non-hello message"),
None => bail!("unexpected EOF"),
};
info!(remote_port, "connected to server");
info!("listening at {to}:{remote_port}");
Ok(Client {
conn: Some(stream),
to: to.to_string(),
local_host: local_host.to_string(),
local_port,
remote_port,
auth,
})
}
/// Returns the port publicly available on the remote.
pub fn remote_port(&self) -> u16 {
self.remote_portView on GitHub (pinned to 00a735a899)