hashicorp/nomad · error
ws_handshake value is not a boolean: %v
Error message
ws_handshake value is not a boolean: %v
What it means
readWsHandshake parses the ws_handshake query parameter as a boolean to decide whether a websocket handshake message is required. This error is returned when the parameter is present but strconv.ParseBool cannot parse it, so the request is malformed before any upgrade.
Source
Thrown at command/agent/websockets.go:145
conn.WriteMessage(websocket.CloseMessage,
websocket.FormatCloseMessage(websocket.CloseNormalClosure, "request complete"))
return nil, nil
}
}
type wsHandshakeMessage struct {
Version int `json:"version"`
AuthToken string `json:"auth_token"`
}
// readWsHandshake reads the websocket handshake message and returns the auth token
func (s *HTTPServer) readWsHandshake(readFn func(any) error, req *http.Request) (string, error) {
// Avoid handshake if request doesn't require one
if hv := req.URL.Query().Get("ws_handshake"); hv == "" {
return "", nil
} else if h, err := strconv.ParseBool(hv); err != nil {
return "", fmt.Errorf("ws_handshake value is not a boolean: %v", err)
} else if !h {
return "", nil
}
// verify that any header token set by a non-browser client agrees with the
// auth header
reqToken := new(string)
s.parseToken(req, reqToken)
var h wsHandshakeMessage
err := readFn(&h)
if err != nil {
return "", err
}
if reqToken != nil && *reqToken != "" && *reqToken != h.AuthToken {
return "", fmt.Errorf("handshake auth token mismatched auth header token")
}View on GitHub (pinned to 482b49bf1a)
Solutions
- Send ws_handshake=true or ws_handshake=false (or 1/0, t/f) — exactly the literals strconv.ParseBool accepts.
- Omit the ws_handshake parameter entirely when no handshake is needed (empty means skip).
- Fix the client code constructing the URL to pass a real boolean, not a string.
- Update wrapper scripts/SDKs that interpolate malformed query values.
Example fix
// before url := base + "/exec?ws_handshake=yes" // after url := base + "/exec?ws_handshake=true"
Defensive patterns
Strategy: validation
Validate before calling
hv := req.URL.Query().Get("ws_handshake")
if hv != "" {
if _, err := strconv.ParseBool(hv); err != nil {
http.Error(w, "ws_handshake must be a boolean", http.StatusBadRequest)
return
}
} Try / catch
if _, err := strconv.ParseBool(hv); err != nil {
http.Error(w, fmt.Sprintf("ws_handshake value is not a boolean: %v", err), http.StatusBadRequest)
return
} Prevention
- Always serialize booleans with strconv.FormatBool when building URLs.
- Validate query params on the client before dispatching the request.
- Keep SDK/wrapper templates typed (bool), not string-interpolated.
- Document accepted literals (true/false/1/0/t/f).
When it happens
Trigger: Client hits a websocket endpoint with e.g. ?ws_handshake=yes or ?ws_handshake=1.0 — any value outside strconv.ParseBool's accepted set (1, t, T, TRUE, true, True, 0, f, F, FALSE, false, False).
Common situations: Hand-rolled websocket clients or templates interpolating strings into the query string; proxies rewriting boolean query values; users typing 'yes'/'on' by intuition.
Understand the failure class
Background: "Invalid query parameter" / "Failed to parse value of ...": fixing bad query string parameters across APIs — this error's family across 36 libraries.
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- PluginID is required
- VolumeID is required
- ExternalID is required
- The '-template' flag is only valid when using 'go-template'
- A template must be supplied using '-template' when using go-
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/ac3882fab84e4f88.
Report an issue: GitHub.