hashicorp/nomad · error

invalid websocket connection in context

Error message

invalid websocket connection in context

What it means

Type-guard failure in getWebsocketConnection: the request context lacks a *websocket.Conn under ctxKeyWebSocketConn (the value is missing or of the wrong type), meaning the audit wrapper did not attach an upgraded connection; callers allocExec/jobRunAction then abort.

Source

Thrown at command/agent/websockets.go:184

	if h.Version != supportedWSHandshakeVersion {
		return "", fmt.Errorf("unexpected handshake value: %v", h.Version)
	}

	return h.AuthToken, nil
}

// getWebsocketConnection retrieves the websocket connection from context
func (s *HTTPServer) getWebsocketConnection(req *http.Request) (*websocket.Conn, error) {
	ctx := req.Context()

	// Get websocket connection from context (set by audit wrapper)
	connRaw := ctx.Value(ctxKeyWebSocketConn)
	if connRaw == nil {
		return nil, fmt.Errorf("websocket connection not found in context")
	}
	conn, ok := connRaw.(*websocket.Conn)
	if !ok {
		return nil, fmt.Errorf("invalid websocket connection in context")
	}

	return conn, nil
}

// runWebsocketWatcher reads messages from a websocket using the watcher
// protocol. That usage does not read from the websocket, but reads are
// required to receive control messages so this will continually read
// the websocket until an error is encountered.
func (s *HTTPServer) runWebsocketWatcher(conn *websocket.Conn) {
	for {
		if _, _, err := conn.ReadMessage(); err != nil {
			s.logger.Trace("watcher websocket reader encountered error, stopping read", "error", err)
			return
		}
	}
}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Fix the middleware responsible so it stores a *websocket.Conn under ctxKeyWebSocketConn.
  2. Audit all uses of ctxKeyWebSocketConn for key collisions and consolidate on one setter.
  3. Update tests/mocks to inject an actual *websocket.Conn (or the shared key with correct type).
  4. Re-run against stock Nomad to rule out a fork/patched binary storing a wrong type.

Example fix

// before
ctx = context.WithValue(ctx, ctxKeyWebSocketConn, myConnWrapper)
// after
ctx = context.WithValue(ctx, ctxKeyWebSocketConn, wsConn) // *websocket.Conn
Defensive patterns

Strategy: type-guard

Validate before calling

connRaw := ctx.Value(ctxKeyWebSocketConn)
conn, ok := connRaw.(*websocket.Conn)
if !ok {
    return nil, fmt.Errorf("invalid websocket connection in context: %T", connRaw)
}

Try / catch

conn, err := s.getWebsocketConnection(req)
if err != nil {
    log.Printf("ws context corruption (check middleware types): %v", err)
    return err
}

Prevention

When it happens

Trigger: getWebsocketConnection (called by allocExec/jobRunAction) finds ctx.Value(ctxKeyWebSocketConn) non-nil but of a different concrete type — caused by another middleware storing a conflicting value under the same key or a refactor changing the stored type.

Common situations: Two wrappers using the same context key for different purposes; custom middleware patched in; tests injecting a mock connection of the wrong type into the request context.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/6f6f3d717dbd8d30. Report an issue: GitHub.