or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

asgi-integration.mdasync-websocket.mdexceptions.mdindex.mdsync-websocket.md

exceptions.mddocs/

0

# Exception Handling

1

2

Simple WebSocket provides specific exception classes for handling WebSocket-related errors. These exceptions provide detailed information about connection failures and closures, enabling proper error handling and recovery strategies.

3

4

## Capabilities

5

6

### Base Exception Class

7

8

Base exception class for all simple-websocket related errors, serving as the parent class for WebSocket-specific exceptions.

9

10

```python { .api }

11

class SimpleWebsocketError(RuntimeError):

12

"""

13

Base exception class for all simple-websocket related errors.

14

15

Inherits from RuntimeError and serves as the parent class for all

16

WebSocket-specific exceptions in the simple-websocket library.

17

"""

18

```

19

20

### Connection Error Exception

21

22

Exception raised when WebSocket connection cannot be established or encounters an error during operation.

23

24

```python { .api }

25

class ConnectionError(SimpleWebsocketError):

26

"""

27

Connection error exception class.

28

29

Raised when:

30

- WebSocket handshake fails

31

- Invalid server response during connection

32

- Network connectivity issues

33

- SSL/TLS certificate errors

34

- Server rejection of connection

35

"""

36

37

def __init__(self, status_code=None):

38

"""

39

Initialize connection error.

40

41

Parameters:

42

- status_code: HTTP status code associated with the error (optional)

43

"""

44

```

45

46

### Connection Closed Exception

47

48

Exception raised when WebSocket connection is closed, either by the remote peer or due to protocol violations.

49

50

```python { .api }

51

class ConnectionClosed(SimpleWebsocketError):

52

"""

53

Connection closed exception class.

54

55

Raised when:

56

- Remote peer closes the connection

57

- Connection is closed due to protocol violation

58

- Network connection is lost

59

- Maximum message size exceeded

60

- Ping/pong timeout occurs

61

"""

62

63

def __init__(self, reason=None, message=None):

64

"""

65

Initialize connection closed exception.

66

67

Parameters:

68

- reason: CloseReason enum value indicating why connection was closed

69

- message: Optional text message describing the closure

70

"""

71

```

72

73

### Exception Attributes

74

75

```python { .api }

76

class ConnectionError:

77

status_code: int | None # HTTP status code if available

78

79

class ConnectionClosed:

80

reason: CloseReason # Close reason code from WebSocket protocol

81

message: str | None # Optional close message text

82

```

83

84

## Close Reason Codes

85

86

WebSocket connections can be closed for various reasons. The `ConnectionClosed` exception includes a reason code that indicates why the connection was terminated:

87

88

### Standard Close Codes

89

90

- **1000 (Normal Closure)**: Connection completed successfully

91

- **1001 (Going Away)**: Server going down or browser navigating away

92

- **1002 (Protocol Error)**: WebSocket protocol error

93

- **1003 (Unsupported Data)**: Unsupported data type received

94

- **1005 (No Status Received)**: No close status code was provided

95

- **1006 (Abnormal Closure)**: Connection closed abnormally

96

- **1007 (Invalid Data)**: Invalid UTF-8 data received

97

- **1008 (Policy Violation)**: Message violates endpoint policy

98

- **1009 (Message Too Big)**: Message too large to process

99

- **1010 (Missing Extension)**: Required extension not negotiated

100

- **1011 (Internal Error)**: Server encountered unexpected condition

101

- **1015 (TLS Handshake)**: TLS handshake failure

102

103

## Usage Examples

104

105

### Basic Error Handling

106

107

```python

108

import simple_websocket

109

110

def handle_websocket_connection():

111

try:

112

# Attempt to connect

113

ws = simple_websocket.Client.connect("ws://localhost:8000/ws")

114

115

# Send and receive messages

116

ws.send("Hello, Server!")

117

response = ws.receive(timeout=10)

118

print(f"Response: {response}")

119

120

except simple_websocket.ConnectionError as e:

121

print(f"Failed to connect: {e}")

122

if e.status_code:

123

print(f"HTTP Status: {e.status_code}")

124

125

except simple_websocket.ConnectionClosed as e:

126

print(f"Connection was closed: {e}")

127

print(f"Close reason: {e.reason}")

128

if e.message:

129

print(f"Close message: {e.message}")

130

131

except Exception as e:

132

print(f"Unexpected error: {e}")

133

134

finally:

135

# Always clean up

136

try:

137

ws.close()

138

except:

139

pass # Connection may already be closed

140

```

141

142

### Async Error Handling

143

144

```python

145

import asyncio

146

import simple_websocket

147

148

async def async_websocket_handler():

149

ws = None

150

try:

151

# Attempt async connection

152

ws = await simple_websocket.AioClient.connect("wss://secure-server.com/ws")

153

154

# Send message and wait for response

155

await ws.send("Hello, Async Server!")

156

response = await ws.receive(timeout=15)

157

print(f"Server response: {response}")

158

159

except simple_websocket.ConnectionError as e:

160

print(f"Connection failed: {e}")

161

if e.status_code == 403:

162

print("Access forbidden - check authentication")

163

elif e.status_code == 404:

164

print("WebSocket endpoint not found")

165

elif e.status_code >= 500:

166

print("Server error - try again later")

167

168

except simple_websocket.ConnectionClosed as e:

169

print(f"Connection closed: {e}")

170

171

# Handle different close reasons

172

if e.reason == 1000: # Normal closure

173

print("Connection closed normally")

174

elif e.reason == 1001: # Going away

175

print("Server is shutting down")

176

elif e.reason == 1008: # Policy violation

177

print("Message violated server policy")

178

elif e.reason == 1009: # Message too big

179

print("Message was too large")

180

else:

181

print(f"Connection closed with code: {e.reason}")

182

183

except asyncio.TimeoutError:

184

print("Timeout waiting for server response")

185

186

finally:

187

if ws:

188

await ws.close()

189

190

# Run the async handler

191

asyncio.run(async_websocket_handler())

192

```

193

194

### Server Error Handling

195

196

```python

197

import simple_websocket

198

199

def websocket_server_handler(environ, start_response):

200

ws = None

201

try:

202

# Accept WebSocket connection

203

ws = simple_websocket.Server.accept(

204

environ,

205

subprotocols=['chat', 'echo'],

206

max_message_size=1024 * 1024 # 1MB limit

207

)

208

209

print(f"Client connected with subprotocol: {ws.subprotocol}")

210

211

while True:

212

try:

213

# Receive message with timeout

214

message = ws.receive(timeout=30)

215

216

if message is None:

217

# Timeout occurred

218

print("Client timeout - closing connection")

219

ws.close(reason=1000, message="Timeout")

220

break

221

222

# Echo the message

223

ws.send(f"Echo: {message}")

224

225

except simple_websocket.ConnectionClosed as e:

226

print(f"Client disconnected: {e}")

227

if e.reason == 1001:

228

print("Client navigated away")

229

elif e.reason == 1006:

230

print("Connection lost unexpectedly")

231

break

232

233

except simple_websocket.ConnectionError as e:

234

print(f"Failed to establish WebSocket connection: {e}")

235

if e.status_code == 400:

236

print("Bad WebSocket request")

237

elif e.status_code == 426:

238

print("Upgrade required")

239

240

except Exception as e:

241

print(f"Unexpected server error: {e}")

242

243

finally:

244

if ws:

245

try:

246

ws.close(reason=1011, message="Server error")

247

except:

248

pass # Connection may already be closed

249

```

250

251

### Custom Exception Handling

252

253

```python

254

import simple_websocket

255

from wsproto.frame_protocol import CloseReason

256

257

class WebSocketManager:

258

def __init__(self):

259

self.ws = None

260

self.reconnect_attempts = 0

261

self.max_reconnect_attempts = 3

262

263

async def connect_with_retry(self, url):

264

"""Connect with automatic retry logic."""

265

while self.reconnect_attempts < self.max_reconnect_attempts:

266

try:

267

self.ws = await simple_websocket.AioClient.connect(url)

268

self.reconnect_attempts = 0 # Reset on successful connection

269

return True

270

271

except simple_websocket.ConnectionError as e:

272

self.reconnect_attempts += 1

273

print(f"Connection attempt {self.reconnect_attempts} failed: {e}")

274

275

if e.status_code == 401:

276

print("Authentication required - cannot retry")

277

return False

278

elif e.status_code == 404:

279

print("Endpoint not found - cannot retry")

280

return False

281

elif self.reconnect_attempts < self.max_reconnect_attempts:

282

await asyncio.sleep(2 ** self.reconnect_attempts) # Exponential backoff

283

284

print("Max reconnection attempts reached")

285

return False

286

287

async def handle_message_loop(self):

288

"""Handle messages with comprehensive error handling."""

289

try:

290

while True:

291

message = await self.ws.receive(timeout=60)

292

293

if message is None:

294

# Send ping to keep connection alive

295

await self.ws.send("ping")

296

continue

297

298

# Process message

299

await self.process_message(message)

300

301

except simple_websocket.ConnectionClosed as e:

302

print(f"Connection closed: {e}")

303

304

# Decide whether to reconnect based on close reason

305

should_reconnect = e.reason in [

306

CloseReason.GOING_AWAY, # 1001

307

CloseReason.ABNORMAL_CLOSURE, # 1006

308

CloseReason.INTERNAL_ERROR # 1011

309

]

310

311

if should_reconnect:

312

print("Attempting to reconnect...")

313

return await self.connect_with_retry(self.url)

314

else:

315

print("Connection closed permanently")

316

return False

317

318

async def process_message(self, message):

319

"""Process received message."""

320

try:

321

# Your message processing logic here

322

print(f"Processing: {message}")

323

await self.ws.send(f"Processed: {message}")

324

325

except Exception as e:

326

print(f"Error processing message: {e}")

327

# Send error response

328

await self.ws.send(f"Error: {str(e)}")

329

```

330

331

## Best Practices

332

333

### 1. Always Handle Both Exception Types

334

335

```python

336

try:

337

# WebSocket operations

338

pass

339

except simple_websocket.ConnectionError as e:

340

# Handle connection establishment errors

341

pass

342

except simple_websocket.ConnectionClosed as e:

343

# Handle connection closure

344

pass

345

```

346

347

### 2. Check Close Reasons for Appropriate Response

348

349

```python

350

except simple_websocket.ConnectionClosed as e:

351

if e.reason in [1000, 1001]: # Normal closures

352

# Clean shutdown

353

pass

354

elif e.reason in [1002, 1003, 1007]: # Protocol errors

355

# Log error, don't retry

356

pass

357

elif e.reason in [1006, 1011]: # Abnormal/server errors

358

# Consider reconnection

359

pass

360

```

361

362

### 3. Use Finally Blocks for Cleanup

363

364

```python

365

try:

366

# WebSocket operations

367

pass

368

except simple_websocket.ConnectionError:

369

# Handle errors

370

pass

371

finally:

372

# Always cleanup resources

373

if ws:

374

try:

375

ws.close()

376

except:

377

pass # Ignore cleanup errors

378

```