vi/websocat · error

Request URI doesn't match --restrict-uri parameter

Error message

Request URI doesn't match --restrict-uri parameter

What it means

Raised during WebSocket upgrade in ws_upgrade_peer when the request URI does not equal the --restrict-uri parameter value. The check requires the request's absolute path to match restrict_uri exactly (AbsolutePath == restrict_uri); on failure the server rejects the handshake, logs a warning, and returns simple_err wrapped as a WebSocketError::IoError. This enforces that the server only accepts upgrades at one specific path.

Solutions

  1. Connect to the exact path given in --restrict-uri (e.g. ws://host:8080/echo when --restrict-uri=/echo), including no trailing slash.
  2. If the path is intentional, update --restrict-uri on the server to match it and restart.
  3. Remove the --restrict-uri option if any path should be accepted.
  4. Check reverse-proxy configuration for path rewrites/strips that alter the URI before it reaches the server.

Example fix

// before: server started with --restrict-uri=/echo but client hits another path
const ws = new WebSocket("ws://host:8080/");

// after
const ws = new WebSocket("ws://host:8080/echo");
Defensive patterns

Strategy: validation

Validate before calling

// Client-side pre-check before connecting (JS)
const restrictUri = "/echo"; // mirrors server --restrict-uri
const path = new URL(wsUrl).pathname;
if (path !== restrictUri) throw new Error(`path ${path} does not match --restrict-uri ${restrictUri}`);

Try / catch

ws.addEventListener("error", () => {
  // rejected handshake: request URI did not match --restrict-uri
  console.error("Upgrade rejected: URI does not match --restrict-uri");
});

Prevention

When it happens

Trigger: A client sends a WebSocket upgrade whose request path differs from --restrict-uri (e.g. server started with --restrict-uri=/echo but the client connects to / or /other), including trailing-slash or query-string/path-case differences that break exact comparison.

Common situations: Client URL path edited or defaulted to '/' while --restrict-uri is set; reverse proxy rewriting the path before it reaches the server; mismatch between a documented endpoint and the restrict-uri flag; trailing slash ('/echo/' vs '/echo').

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


AI-assisted analysis of vi/websocat@3a3574cd2f (2026-09-12). Data as JSON: /api/errors/f7603d60fe13ad15. Report an issue: GitHub.

Appendix: source

Thrown at src/ws_server_peer.rs:237

                                    warn!("Header {} value contains invalid UTF-8", q);
                                }
                            } else {
                                warn!("No request header {}, so no envvar H_{}", q, q);
                            }
                        }
                    },
                    L2rUser::ReadFrom(_) => {},
                }
                
                
                if let Some(ref restrict_uri) = *restrict_uri {
                    let check_passed = matches!(x.request.subject.1, AbsolutePath(ref x) if x == restrict_uri);
                    if !check_passed {
                        return Box::new(
                            x.reject()
                                .and_then(|_| {
                                    warn!("Incoming request URI doesn't match the --restrict-uri value");
                                    ::futures::future::err(crate::util::simple_err(
                                        "Request URI doesn't match --restrict-uri parameter"
                                            .to_string(),
                                    ))
                                })
                                .map_err(|e| websocket::WebSocketError::IoError(io_other_error(e))),
                        )
                            as Box<dyn Future<Item = Peer, Error = websocket::WebSocketError>>;
                    }
                };
                Box::new(x.accept_with_limits(opts.max_ws_frame_length, opts.max_ws_message_length).map(move |(y, headers)| {
                    debug!("{:?}", headers);
                    info!("Upgraded");
                    let close_on_shutdown =  !opts.websocket_dont_close;
                    super::ws_peer::finish_building_ws_peer(&opts, y, close_on_shutdown, None)
                })) as Box<dyn Future<Item = Peer, Error = websocket::WebSocketError>>
            },
        );
    let step4 = step3.map_err(box_up_err);

View on GitHub (pinned to 3a3574cd2f)