Handshake status 403 Forbidden -±±

025-11-10 14:13:06 - main - INFO - :bar_chart: Starting continuous risk monitoring
2025-11-10 14:13:07,129 - WebSocketMarketDataManager - ERROR - :collision: [FIXED] === EVENT: WebSocket error ===
2025-11-10 14:13:07,162 - WebSocketMarketDataManager - ERROR - :collision: [FIXED] Error: Handshake status 403 Forbidden -±± {‘date’: ‘Mon, 10 Nov 2025 08:43:10 GMT’, ‘transfer-encoding’: ‘chunked’, ‘connection’: ‘keep-alive’} -±± None
2025-11-10 14:13:07 - websocket - ERROR - Handshake status 403 Forbidden -±± {‘date’: ‘Mon, 10 Nov 2025 08:43:10 GMT’, ‘transfer-encoding’: ‘chunked’, ‘connection’: ‘keep-alive’} -±± None - goodbye
2025-11-10 14:13:07,708 - WebSocketMarketDataManager - ERROR - :collision: [FIXED] === EVENT: WebSocket error ===
2025-11-10 14:13:07,709 - WebSocketMarketDataManager - ERROR - :collision: [FIXED] Error: Handshake status 403 Forbidden -±± {‘date’: ‘Mon, 10 Nov 2025 08:43:11 GMT’, ‘transfer-encoding’: ‘chunked’, ‘connection’: ‘keep-alive’} -±± None
2025-11-10 14:13:08 - websocket - ERROR - Handshake status 403 Forbidden -±± {‘date’: ‘Mon, 10 Nov 2025 08:43:11 GMT’, ‘transfer-encoding’: ‘chunked’, ‘connection’: ‘keep-alive’} -±± None - goodbye
2025-11-10 14:13:08,963 - WebSocketMarketDataManager - ERROR - :collision: [FIXED] === EVENT: WebSocket error ===
2025-11-10 14:13:08,964 - WebSocketMarketDataManager - ERROR - :collision: [FIXED] Error: Handshake status 403 Forbidden -±± {‘date’: ‘Mon, 10 Nov 2025 08:43:12 GMT’, ‘transfer-encoding’: ‘chunked’, ‘connection’: ‘keep-alive’} -±± None
2025-11-10 14:13:09 - websocket - ERROR - Handshake status 403 Forbidden -±± {‘date’: ‘Mon, 10 Nov 2025 08:43:12 GMT’, ‘transfer-encoding’: ‘chunked’, ‘connection’: ‘keep-alive’} -±± None - goodbye
2025-11-10 14:13:11,201 - WebSocketMarketDataManager - ERROR - :collision: [FIXED] === EVENT: WebSocket error ===
2025-11-10 14:13:11,204 - WebSocketMarketDataManager - ERROR - :collision: [FIXED] Error: Handshake status 403 Forbidden -±± {‘date’: ‘Mon, 10 Nov 2025 08:43:15 GMT’, ‘transfer-encoding’: ‘chunked’, ‘connection’: ‘keep-alive’} -±± None
2025-11-10 14:13:12 - websocket - ERROR - Handshake status 403 Forbidden -±± {‘date’: ‘Mon, 10 Nov 2025 08:43:15 GMT’, ‘transfer-encoding’: ‘chunked’, ‘connection’: ‘keep-alive’} -±± None - goodbye
2025-11-10 14:13:12,448 - WebSocketMarketDataManager - ERROR - :collision: [FIXED] === EVENT: WebSocket error ===
2025-11-10 14:13:12,448 - WebSocketMarketDataManager - ERROR - :collision: [FIXED] Error: Handshake status 403 Forbidden -±± {‘date’: ‘Mon, 10 Nov 2025 08:43:16 GMT’, ‘transfer-encoding’: ‘chunked’, ‘connection’: ‘keep-alive’} -±± None
2025-11-10 14:13:13 - websocket - ERROR - Handshake status 403 Forbidden -±± {‘date’: ‘Mon, 10 Nov 2025 08:43:16 GMT’, ‘transfer-encoding’: ‘chunked’, ‘connection’: ‘keep-alive’} -±± None - goodbye
2025-11-10 14:13:13,598 - WebSocketMarketDataManager - ERROR - :collision: [FIXED] === EVENT: WebSocket error ===
2025-11-10 14:13:13,599 - WebSocketMarketDataManager - ERROR - :collision: [FIXED] Error: Handshake status 403 Forbidden -±± {‘date’: ‘Mon, 10 Nov 2025 08:43:17 GMT’, ‘transfer-encoding’: ‘chunked’, ‘connection’: ‘keep-alive’} -±± None
2025-11-10 14:13:13 - websocket - ERROR - Handshake status 403 Forbidden -±± {‘date’: ‘Mon, 10 Nov 2025 08:43:17 GMT’, ‘transfer-encoding’: ‘chunked’, ‘connection’: ‘keep-alive’} -±± None - goodbye

async def initialize_websocket_connection_fixed(self) → bool:
“”"
FIXED: Correct WebSocket implementation - NO 'Bearer ’ prefix for WebSocket
“”"
try:
self.logger.info(“:bullseye: [FIXED] === START: WebSocket initialization - NO BEARER PREFIX ===”)

        # 🚨 CRITICAL: Use direct token loading as shown in examples
        from _01_login import load_access_token
        
        self.logger.info("🔍 [FIXED] Step 1: Loading access token...")
        access_token = load_access_token()
        self.logger.info(f"🔍 [FIXED] load_access_token() returned: {type(access_token)}")
        
        if not access_token:
            self.logger.error("❌ [FIXED] FAIL: Cannot load access token - token is None or empty")
            return False
            
        # 🚨🚨🚨 CRITICAL FIX: REMOVE 'Bearer ' prefix for WebSocket
        self.logger.info(f"🔍 [FIXED] Original token length: {len(access_token)}")
        self.logger.info(f"🔍 [FIXED] Original token starts with 'Bearer ': {access_token.startswith('Bearer ')}")
        
        # 🚨 IMPORTANT: WebSocket requires token WITHOUT 'Bearer ' prefix
        if access_token.startswith('Bearer '):
            self.logger.warning("⚠️ [FIXED] Token has 'Bearer ' prefix - REMOVING it for WebSocket")
            final_token = access_token.replace('Bearer ', '')
            self.logger.info("✅ [FIXED] Removed 'Bearer ' prefix from token")
        else:
            self.logger.info("✅ [FIXED] Token already without 'Bearer ' prefix - using as-is")
            final_token = access_token
            
        self.logger.info(f"✅ [FIXED] Final token length: {len(final_token)} characters")
        self.logger.info(f"🔍 [FIXED] Final token first 50 chars: '{final_token[:50]}'")
        self.logger.info(f"🔍 [FIXED] Final token starts with 'Bearer ': {final_token.startswith('Bearer ')}")
        
        # ✅ CORRECT: Create configuration exactly like SDK examples
        self.logger.info("🔍 [FIXED] Step 2: Creating configuration...")
        configuration = upstox_client.Configuration()
        configuration.access_token = final_token
        self.logger.info(f"✅ [FIXED] Configuration access_token set: {bool(configuration.access_token)}")
        
        # ✅ CORRECT: Create API client with configuration
        self.logger.info("🔍 [FIXED] Step 3: Creating API client...")
        api_client = upstox_client.ApiClient(configuration)
        self.logger.info(f"✅ [FIXED] API client created: {api_client is not None}")
        
        # 🔍 Validate instrument keys
        self.logger.info("🔍 [FIXED] Step 4: Validating instrument keys...")
        valid_instruments = []
        for i, instrument in enumerate(self.instrument_keys):
            if isinstance(instrument, str) and '|' in instrument:
                valid_instruments.append(instrument)
                self.logger.info(f"✅ [FIXED] Instrument {i+1} VALID: '{instrument}'")
            else:
                self.logger.error(f"❌ [FIXED] Instrument {i+1} INVALID: '{instrument}'")
        
        if not valid_instruments:
            self.logger.error("❌ [FIXED] No valid instruments found")
            return False
            
        self.logger.info(f"🔍 [FIXED] Subscription mode: '{self.subscription_mode}'")
        self.logger.info(f"📡 [FIXED] Creating MarketDataStreamerV3 for {len(valid_instruments)} instruments")

        try:
            # ✅ CORRECT: Initialize streamer with validated parameters
            self.streamer_v3 = upstox_client.MarketDataStreamerV3(
                api_client, 
                valid_instruments, 
                self.subscription_mode
            )
            self.logger.info("✅ [FIXED] MarketDataStreamerV3 created successfully")
            
        except Exception as e:
            self.logger.error(f"❌ [FIXED] FAIL: Failed to create MarketDataStreamerV3: {e}")
            return False

        # 🚨 CRITICAL: Register handlers BEFORE connecting
        self.logger.info("🔍 [FIXED] Step 5: Setting up event handlers...")
        connection_established = asyncio.Event()
        
        def on_open():
            self.logger.info("✅ [FIXED] === EVENT: WebSocket on_open triggered ===")
            self.logger.info("✅ [FIXED] WebSocket connection established!")
            self.is_connected = True
            connection_established.set()
            
        def on_message(message):
            try:
                self._message_counter += 1
                if self._message_counter <= 5:
                    self.logger.info(f"📨 [FIXED] Message #{self._message_counter} received")
                self._handle_market_data_message(message)
            except Exception as e:
                self.logger.error(f"❌ [FIXED] Message handling error: {e}")
                
        def on_error(error):
            error_str = str(error)
            self.logger.error(f"💥 [FIXED] === EVENT: WebSocket error ===")
            self.logger.error(f"💥 [FIXED] Error: {error_str}")
            
            # 🚨 ENHANCED ERROR ANALYSIS
            if "401" in error_str or "Unauthorized" in error_str:
                self.logger.error("🔐 [FIXED] === 401 UNAUTHORIZED ===")
                self.logger.error("🔐 [FIXED] Token authentication failed")
                self.logger.error(f"🔐 [FIXED] Token length: {len(final_token)}")
                self.logger.error(f"🔐 [FIXED] Has 'Bearer ' prefix: {final_token.startswith('Bearer ')}")
                self.logger.error("🔐 [FIXED] Try: Refresh token or check WebSocket permissions")
                
            self.is_connected = False
            
        def on_close(code=None, reason=None):
            self.logger.info(f"🔴 [FIXED] WebSocket closed: {code} - {reason}")
            self.is_connected = False

        # Register handlers
        try:
            self.streamer_v3.on("open", on_open)
            self.streamer_v3.on("message", on_message)
            self.streamer_v3.on("error", on_error)
            self.streamer_v3.on("close", on_close)
            self.logger.info("✅ [FIXED] Event handlers registered")
        except Exception as e:
            self.logger.error(f"❌ [FIXED] Handler registration failed: {e}")
            return False
        
        # Connect
        self.logger.info("🔗 [FIXED] Step 6: Connecting WebSocket...")
        try:
            self.streamer_v3.connect()
            self.logger.info("✅ [FIXED] connect() called")
            
            # Wait for connection
            self.logger.info("⏳ [FIXED] Waiting for connection...")
            await connection_established.wait()
            
            self.logger.info("✅ [FIXED] WebSocket connected successfully!")
            
            # Wait for initial messages
            await asyncio.sleep(3)
            self.logger.info(f"📨 [FIXED] Messages received: {self._message_counter}")
            
            return True
            
        except Exception as e:
            self.logger.error(f"❌ [FIXED] Connection failed: {e}")
            return False
            
    except Exception as e:
        self.logger.error(f"💥 [FIXED] Initialization failed: {e}")
        return False

@Amol_Patil
The 403 Forbidden error occurs when the WebSocket connection or subscription limits are not followed.

Please review the connection and subscription limits mentioned in the official documentation below and ensure your implementation adheres to them:
https://upstox.com/developer/api-documentation/v3/get-market-data-feed#normal-connection-and-subscription-limits

Once the limits are respected, the WebSocket connection should work as expected.