or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

blueprints.mdconfiguration.mdcore-application.mdexceptions.mdindex.mdmiddleware-signals.mdrequest-response.mdserver-deployment.mdwebsockets.md

exceptions.mddocs/

0

# Exception Handling

1

2

Sanic provides a comprehensive exception system with HTTP status code exceptions, custom error handlers, and mechanisms for graceful error handling. The framework includes built-in exceptions for common HTTP errors and supports custom exception handling.

3

4

## Capabilities

5

6

### Base Exception Classes

7

8

Core exception classes that form the foundation of Sanic's error handling system.

9

10

```python { .api }

11

class SanicException(Exception):

12

"""

13

Base exception class for all Sanic exceptions.

14

15

Attributes:

16

- message: Exception message

17

- status_code: HTTP status code (if applicable)

18

- quiet: Whether to suppress logging

19

"""

20

21

def __init__(

22

self,

23

message: str,

24

status_code: int = None,

25

quiet: bool = None,

26

context: dict = None,

27

extra: dict = None,

28

):

29

"""

30

Initialize Sanic exception.

31

32

Parameters:

33

- message: Error message

34

- status_code: HTTP status code

35

- quiet: Suppress logging if True

36

- context: Additional context information

37

- extra: Extra data for exception

38

"""

39

40

class ServerError(SanicException):

41

"""

42

Base class for 5xx server error exceptions.

43

44

Default status_code: 500

45

"""

46

47

class InvalidUsage(SanicException):

48

"""

49

Base class for 4xx client error exceptions.

50

51

Default status_code: 400

52

"""

53

```

54

55

### HTTP Client Error Exceptions (4xx)

56

57

Exceptions for client-side errors with appropriate HTTP status codes.

58

59

```python { .api }

60

class BadRequest(InvalidUsage):

61

"""

62

400 Bad Request exception.

63

64

Raised when the request is malformed or invalid.

65

"""

66

67

def __init__(self, message: str = "Bad Request", **kwargs):

68

super().__init__(message, status_code=400, **kwargs)

69

70

class Unauthorized(InvalidUsage):

71

"""

72

401 Unauthorized exception.

73

74

Raised when authentication is required but missing or invalid.

75

"""

76

77

def __init__(self, message: str = "Unauthorized", **kwargs):

78

super().__init__(message, status_code=401, **kwargs)

79

80

class Forbidden(InvalidUsage):

81

"""

82

403 Forbidden exception.

83

84

Raised when the request is understood but access is denied.

85

"""

86

87

def __init__(self, message: str = "Forbidden", **kwargs):

88

super().__init__(message, status_code=403, **kwargs)

89

90

class NotFound(InvalidUsage):

91

"""

92

404 Not Found exception.

93

94

Raised when the requested resource cannot be found.

95

"""

96

97

def __init__(self, message: str = "Not Found", **kwargs):

98

super().__init__(message, status_code=404, **kwargs)

99

100

class MethodNotAllowed(InvalidUsage):

101

"""

102

405 Method Not Allowed exception.

103

104

Raised when the HTTP method is not allowed for the resource.

105

"""

106

107

def __init__(self, message: str = "Method Not Allowed", **kwargs):

108

super().__init__(message, status_code=405, **kwargs)

109

110

class RangeNotSatisfiable(InvalidUsage):

111

"""

112

416 Range Not Satisfiable exception.

113

114

Raised when the requested range cannot be satisfied.

115

"""

116

117

def __init__(self, message: str = "Range Not Satisfiable", **kwargs):

118

super().__init__(message, status_code=416, **kwargs)

119

120

class ExpectationFailed(InvalidUsage):

121

"""

122

417 Expectation Failed exception.

123

124

Raised when the server cannot meet the Expect request header requirements.

125

"""

126

127

def __init__(self, message: str = "Expectation Failed", **kwargs):

128

super().__init__(message, status_code=417, **kwargs)

129

130

class PayloadTooLarge(InvalidUsage):

131

"""

132

413 Payload Too Large exception.

133

134

Raised when the request payload exceeds size limits.

135

"""

136

137

def __init__(self, message: str = "Payload Too Large", **kwargs):

138

super().__init__(message, status_code=413, **kwargs)

139

140

class RequestTimeout(InvalidUsage):

141

"""

142

408 Request Timeout exception.

143

144

Raised when the request takes too long to process.

145

"""

146

147

def __init__(self, message: str = "Request Timeout", **kwargs):

148

super().__init__(message, status_code=408, **kwargs)

149

```

150

151

### HTTP Server Error Exceptions (5xx)

152

153

Exceptions for server-side errors indicating internal problems.

154

155

```python { .api }

156

class InternalServerError(ServerError):

157

"""

158

500 Internal Server Error exception.

159

160

Raised when an unexpected server error occurs.

161

"""

162

163

def __init__(self, message: str = "Internal Server Error", **kwargs):

164

super().__init__(message, status_code=500, **kwargs)

165

166

class ServiceUnavailable(ServerError):

167

"""

168

503 Service Unavailable exception.

169

170

Raised when the server is temporarily unable to handle requests.

171

"""

172

173

def __init__(self, message: str = "Service Unavailable", **kwargs):

174

super().__init__(message, status_code=503, **kwargs)

175

176

class NotImplemented(ServerError):

177

"""

178

501 Not Implemented exception.

179

180

Raised when the requested functionality is not implemented.

181

"""

182

183

def __init__(self, message: str = "Not Implemented", **kwargs):

184

super().__init__(message, status_code=501, **kwargs)

185

186

class BadGateway(ServerError):

187

"""

188

502 Bad Gateway exception.

189

190

Raised when acting as gateway and receiving invalid response.

191

"""

192

193

def __init__(self, message: str = "Bad Gateway", **kwargs):

194

super().__init__(message, status_code=502, **kwargs)

195

196

class GatewayTimeout(ServerError):

197

"""

198

504 Gateway Timeout exception.

199

200

Raised when acting as gateway and upstream server times out.

201

"""

202

203

def __init__(self, message: str = "Gateway Timeout", **kwargs):

204

super().__init__(message, status_code=504, **kwargs)

205

```

206

207

### Specialized Exceptions

208

209

Framework-specific exceptions for particular scenarios and conditions.

210

211

```python { .api }

212

class HeaderNotFound(SanicException):

213

"""

214

Raised when a required header is missing from the request.

215

"""

216

217

def __init__(self, message: str = "Header not found", **kwargs):

218

super().__init__(message, **kwargs)

219

220

class InvalidHeader(SanicException):

221

"""

222

Raised when a header value is invalid or malformed.

223

"""

224

225

def __init__(self, message: str = "Invalid header", **kwargs):

226

super().__init__(message, **kwargs)

227

228

class FileNotFound(NotFound):

229

"""

230

Raised when a requested file cannot be found.

231

"""

232

233

def __init__(self, message: str = "File not found", **kwargs):

234

super().__init__(message, **kwargs)

235

236

class WebsocketClosed(SanicException):

237

"""

238

Raised when attempting to use a closed WebSocket connection.

239

"""

240

241

def __init__(self, message: str = "WebSocket connection closed", **kwargs):

242

super().__init__(message, **kwargs)

243

244

class InvalidSignal(SanicException):

245

"""

246

Raised when an invalid signal is used.

247

"""

248

249

def __init__(self, message: str = "Invalid signal", **kwargs):

250

super().__init__(message, **kwargs)

251

252

class ContentRangeError(SanicException):

253

"""

254

Raised when there's an error with content range handling.

255

"""

256

257

def __init__(self, message: str = "Content range error", **kwargs):

258

super().__init__(message, **kwargs)

259

260

class HeaderExpectationFailed(SanicException):

261

"""

262

Raised when header expectations cannot be met.

263

"""

264

265

def __init__(self, message: str = "Header expectation failed", **kwargs):

266

super().__init__(message, **kwargs)

267

268

class MethodNotSupported(SanicException):

269

"""

270

Raised when an unsupported HTTP method is used.

271

"""

272

273

def __init__(self, message: str = "Method not supported", **kwargs):

274

super().__init__(message, **kwargs)

275

```

276

277

### Exception Handlers

278

279

Decorators and methods for registering custom exception handlers.

280

281

```python { .api }

282

def exception(*exceptions):

283

"""

284

Decorator for registering exception handlers.

285

286

Parameters:

287

- *exceptions: Exception classes to handle

288

289

Usage:

290

@app.exception(NotFound, FileNotFound)

291

async def handle_not_found(request, exception):

292

return json({"error": "Resource not found"}, status=404)

293

"""

294

295

class ErrorHandler:

296

"""Error handler management for applications and blueprints."""

297

298

def add(self, exception, handler):

299

"""

300

Add exception handler.

301

302

Parameters:

303

- exception: Exception class

304

- handler: Handler function

305

"""

306

307

def lookup(self, exception, route_name: str = None):

308

"""

309

Look up handler for exception.

310

311

Parameters:

312

- exception: Exception instance

313

- route_name: Route name for context

314

315

Returns:

316

Handler function or None

317

"""

318

319

def response(self, request, exception):

320

"""

321

Generate response for exception.

322

323

Parameters:

324

- request: Request object

325

- exception: Exception instance

326

327

Returns:

328

HTTPResponse object

329

"""

330

```

331

332

## Usage Examples

333

334

### Basic Exception Handling

335

336

```python

337

from sanic import Sanic

338

from sanic.response import json

339

from sanic.exceptions import NotFound, ServerError, BadRequest

340

341

app = Sanic("MyApp")

342

343

@app.route("/users/<user_id:int>")

344

async def get_user(request, user_id):

345

user = await fetch_user(user_id)

346

if not user:

347

raise NotFound("User not found")

348

return json({"user": user})

349

350

@app.route("/api/data", methods=["POST"])

351

async def process_data(request):

352

if not request.json:

353

raise BadRequest("JSON data required")

354

355

try:

356

result = await process_user_data(request.json)

357

return json({"result": result})

358

except ValueError as e:

359

raise BadRequest(f"Invalid data: {str(e)}")

360

except Exception as e:

361

raise ServerError("Processing failed")

362

```

363

364

### Custom Exception Handlers

365

366

```python

367

from sanic import Sanic

368

from sanic.response import json

369

from sanic.exceptions import NotFound, ServerError, SanicException

370

371

app = Sanic("MyApp")

372

373

@app.exception(NotFound)

374

async def handle_not_found(request, exception):

375

return json({

376

"error": "Resource not found",

377

"message": str(exception),

378

"path": request.path

379

}, status=404)

380

381

@app.exception(ServerError)

382

async def handle_server_error(request, exception):

383

# Log the error

384

app.logger.error(f"Server error: {exception}")

385

386

return json({

387

"error": "Internal server error",

388

"message": "An unexpected error occurred"

389

}, status=500)

390

391

@app.exception(SanicException)

392

async def handle_sanic_exception(request, exception):

393

"""Catch-all handler for Sanic exceptions."""

394

return json({

395

"error": "Application error",

396

"message": str(exception),

397

"status_code": getattr(exception, "status_code", 500)

398

}, status=getattr(exception, "status_code", 500))

399

```

400

401

### Custom Exception Classes

402

403

```python

404

from sanic.exceptions import SanicException

405

from sanic.response import json

406

407

class ValidationError(SanicException):

408

\"\"\"Custom validation error exception.\"\"\"

409

410

def __init__(self, message: str, field: str = None, **kwargs):

411

super().__init__(message, status_code=422, **kwargs)

412

self.field = field

413

414

class AuthenticationError(SanicException):

415

\"\"\"Custom authentication error exception.\"\"\"

416

417

def __init__(self, message: str = "Authentication failed", **kwargs):

418

super().__init__(message, status_code=401, **kwargs)

419

420

class RateLimitExceeded(SanicException):

421

\"\"\"Custom rate limit exception.\"\"\"

422

423

def __init__(self, message: str = "Rate limit exceeded", retry_after: int = None, **kwargs):

424

super().__init__(message, status_code=429, **kwargs)

425

self.retry_after = retry_after

426

427

# Register handlers for custom exceptions

428

@app.exception(ValidationError)

429

async def handle_validation_error(request, exception):

430

return json({

431

"error": "Validation failed",

432

"message": str(exception),

433

"field": getattr(exception, "field", None)

434

}, status=422)

435

436

@app.exception(AuthenticationError)

437

async def handle_auth_error(request, exception):

438

return json({

439

"error": "Authentication required",

440

"message": str(exception)

441

}, status=401)

442

443

@app.exception(RateLimitExceeded)

444

async def handle_rate_limit(request, exception):

445

headers = {}

446

if hasattr(exception, "retry_after"):

447

headers["Retry-After"] = str(exception.retry_after)

448

449

return json({

450

"error": "Rate limit exceeded",

451

"message": str(exception)

452

}, status=429, headers=headers)

453

```

454

455

### Exception Context and Debugging

456

457

```python

458

from sanic import Sanic

459

from sanic.response import json

460

from sanic.exceptions import SanicException

461

462

app = Sanic("MyApp")

463

464

class DatabaseError(SanicException):

465

\"\"\"Database operation error with context.\"\"\"

466

467

def __init__(self, message: str, query: str = None, **kwargs):

468

context = {"query": query} if query else {}

469

super().__init__(message, status_code=500, context=context, **kwargs)

470

471

@app.exception(DatabaseError)

472

async def handle_database_error(request, exception):

473

# Log detailed error information

474

app.logger.error(f"Database error: {exception}")

475

if hasattr(exception, "context") and exception.context:

476

app.logger.error(f"Query: {exception.context.get('query')}")

477

478

# Return appropriate response

479

if app.config.DEBUG:

480

return json({

481

"error": "Database error",

482

"message": str(exception),

483

"context": getattr(exception, "context", {})

484

}, status=500)

485

else:

486

return json({

487

"error": "Internal server error",

488

"message": "A database error occurred"

489

}, status=500)

490

491

@app.route("/users")

492

async def get_users(request):

493

try:

494

query = "SELECT * FROM users"

495

users = await execute_query(query)

496

return json({"users": users})

497

except Exception as e:

498

raise DatabaseError("Failed to fetch users", query=query)

499

```

500

501

### Blueprint Exception Handlers

502

503

```python

504

from sanic import Blueprint

505

from sanic.response import json

506

from sanic.exceptions import NotFound

507

508

api_bp = Blueprint("api", url_prefix="/api")

509

510

class APIError(SanicException):

511

\"\"\"API-specific error exception.\"\"\"

512

513

def __init__(self, message: str, error_code: str = None, **kwargs):

514

super().__init__(message, status_code=400, **kwargs)

515

self.error_code = error_code

516

517

@api_bp.exception(APIError)

518

async def handle_api_error(request, exception):

519

return json({

520

"error": "API Error",

521

"message": str(exception),

522

"error_code": getattr(exception, "error_code", "UNKNOWN"),

523

"timestamp": datetime.utcnow().isoformat()

524

}, status=exception.status_code)

525

526

@api_bp.exception(NotFound)

527

async def handle_api_not_found(request, exception):

528

return json({

529

"error": "API Resource Not Found",

530

"message": "The requested API endpoint does not exist",

531

"path": request.path

532

}, status=404)

533

534

app.blueprint(api_bp)

535

```