or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

backends.mdcore-jsonrpc.mddispatcher.mdexceptions.mdindex.mdrequests-responses.md

exceptions.mddocs/

0

# Exceptions and Error Handling

1

2

Comprehensive error handling system with predefined JSON-RPC error types, custom exception support, and automatic error response generation. The library provides both JSON-RPC standard errors and Python exception integration.

3

4

## Capabilities

5

6

### JSON-RPC Error Objects

7

8

Core error object representing JSON-RPC errors with code, message, and optional data fields.

9

10

```python { .api }

11

class JSONRPCError:

12

serialize = staticmethod # json.dumps

13

deserialize = staticmethod # json.loads

14

15

def __init__(self, code: int = None, message: str = None, data = None):

16

"""

17

Create JSON-RPC error object.

18

19

Parameters:

20

- code: Error code (integer, -32768 to -32000 reserved)

21

- message: Brief error description (string)

22

- data: Additional error information (any type)

23

"""

24

25

@classmethod

26

def from_json(cls, json_str: str):

27

"""Create error from JSON string."""

28

29

# Properties

30

code: int

31

message: str

32

data # Any type

33

json: str # JSON representation

34

```

35

36

### Predefined Error Types

37

38

Standard JSON-RPC error types with predefined codes and messages.

39

40

```python { .api }

41

class JSONRPCParseError(JSONRPCError):

42

"""Invalid JSON was received by the server."""

43

CODE = -32700

44

MESSAGE = "Parse error"

45

46

class JSONRPCInvalidRequest(JSONRPCError):

47

"""The JSON sent is not a valid Request object."""

48

CODE = -32600

49

MESSAGE = "Invalid Request"

50

51

class JSONRPCMethodNotFound(JSONRPCError):

52

"""The method does not exist / is not available."""

53

CODE = -32601

54

MESSAGE = "Method not found"

55

56

class JSONRPCInvalidParams(JSONRPCError):

57

"""Invalid method parameter(s)."""

58

CODE = -32602

59

MESSAGE = "Invalid params"

60

61

class JSONRPCInternalError(JSONRPCError):

62

"""Internal JSON-RPC error."""

63

CODE = -32603

64

MESSAGE = "Internal error"

65

66

class JSONRPCServerError(JSONRPCError):

67

"""Reserved for implementation-defined server-errors."""

68

CODE = -32000

69

MESSAGE = "Server error"

70

```

71

72

### Python Exception Classes

73

74

Standard Python exceptions for different error conditions.

75

76

```python { .api }

77

class JSONRPCException(Exception):

78

"""Base JSON-RPC exception."""

79

pass

80

81

class JSONRPCInvalidRequestException(JSONRPCException):

82

"""Request is not valid."""

83

pass

84

85

class JSONRPCDispatchException(JSONRPCException):

86

"""

87

JSON-RPC dispatch exception for method implementations.

88

89

Should be thrown in dispatch methods to return custom errors.

90

"""

91

92

def __init__(self, code: int = None, message: str = None, data = None, *args, **kwargs):

93

"""

94

Create dispatch exception with error details.

95

96

Parameters:

97

- code: JSON-RPC error code

98

- message: Error message

99

- data: Additional error data

100

- args, kwargs: Standard exception arguments

101

"""

102

103

error: JSONRPCError # Associated error object

104

```

105

106

### Error Detection Utilities

107

108

Utility functions for detecting and validating parameter errors.

109

110

```python { .api }

111

def is_invalid_params(func, *args, **kwargs) -> bool:

112

"""

113

Check if function parameters are invalid.

114

115

Used internally to distinguish TypeError from invalid parameters

116

vs TypeError from within the function.

117

118

Parameters:

119

- func: Function to validate against

120

- args: Positional arguments

121

- kwargs: Keyword arguments

122

123

Returns:

124

True if parameters are invalid for the function

125

"""

126

```

127

128

## Usage Examples

129

130

### Basic Error Handling

131

132

```python

133

from jsonrpc import dispatcher, JSONRPCResponseManager

134

from jsonrpc.exceptions import JSONRPCDispatchException

135

136

@dispatcher.add_method

137

def divide(a, b):

138

if b == 0:

139

raise JSONRPCDispatchException(

140

code=-32602,

141

message="Division by zero",

142

data={"dividend": a, "divisor": b}

143

)

144

return a / b

145

146

@dispatcher.add_method

147

def validate_age(age):

148

if not isinstance(age, int) or age < 0:

149

raise JSONRPCDispatchException(

150

code=-32602,

151

message="Invalid age parameter",

152

data={"received": age, "expected": "positive integer"}

153

)

154

return {"valid": True, "age": age}

155

156

# Error response

157

request = '{"jsonrpc": "2.0", "method": "divide", "params": [10, 0], "id": 1}'

158

response = JSONRPCResponseManager.handle(request, dispatcher)

159

print(response.json)

160

# {

161

# "jsonrpc": "2.0",

162

# "error": {

163

# "code": -32602,

164

# "message": "Division by zero",

165

# "data": {"dividend": 10, "divisor": 0}

166

# },

167

# "id": 1

168

# }

169

```

170

171

### Predefined Error Types

172

173

```python

174

from jsonrpc.exceptions import (

175

JSONRPCMethodNotFound,

176

JSONRPCInvalidParams,

177

JSONRPCInternalError

178

)

179

180

# Method not found (automatically handled by manager)

181

request = '{"jsonrpc": "2.0", "method": "nonexistent", "id": 1}'

182

response = JSONRPCResponseManager.handle(request, dispatcher)

183

print(response.json)

184

# {"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found"}, "id": 1}

185

186

# Invalid parameters (automatically detected)

187

@dispatcher.add_method

188

def greet(name, greeting="Hello"):

189

return f"{greeting}, {name}!"

190

191

# Missing required parameter

192

request = '{"jsonrpc": "2.0", "method": "greet", "params": [], "id": 1}'

193

response = JSONRPCResponseManager.handle(request, dispatcher)

194

print(response.json)

195

# {"jsonrpc": "2.0", "error": {"code": -32602, "message": "Invalid params", "data": {...}}, "id": 1}

196

197

# Too many parameters

198

request = '{"jsonrpc": "2.0", "method": "greet", "params": ["Alice", "Hi", "Extra"], "id": 1}'

199

response = JSONRPCResponseManager.handle(request, dispatcher)

200

print(response.json)

201

# {"jsonrpc": "2.0", "error": {"code": -32602, "message": "Invalid params", "data": {...}}, "id": 1}

202

```

203

204

### Custom Error Creation

205

206

```python

207

from jsonrpc.exceptions import JSONRPCError

208

209

# Create custom error

210

custom_error = JSONRPCError(

211

code=-32001,

212

message="Database connection failed",

213

data={

214

"database": "users",

215

"host": "localhost:5432",

216

"timestamp": "2023-01-01T12:00:00Z"

217

}

218

)

219

220

print(custom_error.json)

221

# {

222

# "code": -32001,

223

# "message": "Database connection failed",

224

# "data": {

225

# "database": "users",

226

# "host": "localhost:5432",

227

# "timestamp": "2023-01-01T12:00:00Z"

228

# }

229

# }

230

231

# Use in dispatch exception

232

@dispatcher.add_method

233

def get_user(user_id):

234

try:

235

# Simulate database operation

236

if user_id == 999:

237

raise ConnectionError("Database unavailable")

238

return {"id": user_id, "name": f"User {user_id}"}

239

except ConnectionError as e:

240

raise JSONRPCDispatchException(

241

code=-32001,

242

message="Database connection failed",

243

data={"error": str(e), "user_id": user_id}

244

)

245

```

246

247

### Error Response Structure

248

249

```python

250

from jsonrpc.exceptions import JSONRPCError

251

from jsonrpc.jsonrpc2 import JSONRPC20Response

252

253

# Manual error response creation

254

error = JSONRPCError(

255

code=-32603,

256

message="Internal error",

257

data={"component": "user_service", "error_id": "USR_001"}

258

)

259

260

response = JSONRPC20Response(error=error._data, _id=123)

261

print(response.json)

262

# {

263

# "jsonrpc": "2.0",

264

# "error": {

265

# "code": -32603,

266

# "message": "Internal error",

267

# "data": {"component": "user_service", "error_id": "USR_001"}

268

# },

269

# "id": 123

270

# }

271

```

272

273

### Parse and Request Errors

274

275

```python

276

from jsonrpc import JSONRPCResponseManager

277

278

# Parse error (invalid JSON)

279

invalid_json = '{"jsonrpc": "2.0", "method": "test", invalid}'

280

response = JSONRPCResponseManager.handle(invalid_json, dispatcher)

281

print(response.json)

282

# {"jsonrpc": "2.0", "error": {"code": -32700, "message": "Parse error"}, "id": null}

283

284

# Invalid request structure

285

invalid_request = '{"jsonrpc": "2.0", "params": [1, 2], "id": 1}' # Missing method

286

response = JSONRPCResponseManager.handle(invalid_request, dispatcher)

287

print(response.json)

288

# {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null}

289

290

# Batch with invalid request

291

batch_with_error = '''[

292

{"jsonrpc": "2.0", "method": "add", "params": [1, 2], "id": "1"},

293

{"jsonrpc": "2.0", "params": [3, 4], "id": "2"},

294

{"jsonrpc": "2.0", "method": "multiply", "params": [5, 6], "id": "3"}

295

]'''

296

response = JSONRPCResponseManager.handle(batch_with_error, dispatcher)

297

# Will return error for the invalid request in the batch

298

```

299

300

### Exception Handling in Methods

301

302

```python

303

from jsonrpc.exceptions import JSONRPCDispatchException

304

import logging

305

306

logger = logging.getLogger(__name__)

307

308

@dispatcher.add_method

309

def process_file(filename):

310

try:

311

# Simulate file processing

312

if not filename:

313

raise ValueError("Filename cannot be empty")

314

315

if not filename.endswith('.txt'):

316

raise JSONRPCDispatchException(

317

code=-32602,

318

message="Invalid file type",

319

data={"filename": filename, "supported": [".txt"]}

320

)

321

322

# Simulate processing

323

return {"status": "processed", "filename": filename}

324

325

except ValueError as e:

326

logger.error(f"Validation error: {e}")

327

raise JSONRPCDispatchException(

328

code=-32602,

329

message="Validation failed",

330

data={"error": str(e)}

331

)

332

except Exception as e:

333

logger.exception("Unexpected error processing file")

334

raise JSONRPCDispatchException(

335

code=-32603,

336

message="Internal processing error",

337

data={"filename": filename, "error_type": type(e).__name__}

338

)

339

340

# Test error cases

341

request1 = '{"jsonrpc": "2.0", "method": "process_file", "params": [""], "id": 1}'

342

response1 = JSONRPCResponseManager.handle(request1, dispatcher)

343

# Returns validation error

344

345

request2 = '{"jsonrpc": "2.0", "method": "process_file", "params": ["doc.pdf"], "id": 2}'

346

response2 = JSONRPCResponseManager.handle(request2, dispatcher)

347

# Returns invalid file type error

348

```

349

350

### Error Code Conventions

351

352

```python

353

# Standard JSON-RPC error codes

354

PARSE_ERROR = -32700 # Invalid JSON

355

INVALID_REQUEST = -32600 # Invalid request object

356

METHOD_NOT_FOUND = -32601 # Method doesn't exist

357

INVALID_PARAMS = -32602 # Invalid parameters

358

INTERNAL_ERROR = -32603 # Internal JSON-RPC error

359

360

# Server error range: -32000 to -32099 (reserved for implementation)

361

DATABASE_ERROR = -32001

362

AUTHENTICATION_ERROR = -32002

363

AUTHORIZATION_ERROR = -32003

364

RATE_LIMIT_ERROR = -32004

365

VALIDATION_ERROR = -32005

366

367

# Application-specific errors: -32100 and below

368

USER_NOT_FOUND = -32100

369

INSUFFICIENT_FUNDS = -32101

370

PRODUCT_OUT_OF_STOCK = -32102

371

372

@dispatcher.add_method

373

def transfer_funds(from_account, to_account, amount):

374

if amount <= 0:

375

raise JSONRPCDispatchException(

376

code=VALIDATION_ERROR,

377

message="Invalid transfer amount",

378

data={"amount": amount}

379

)

380

381

# Check balance

382

if get_balance(from_account) < amount:

383

raise JSONRPCDispatchException(

384

code=INSUFFICIENT_FUNDS,

385

message="Insufficient funds for transfer",

386

data={

387

"from_account": from_account,

388

"requested": amount,

389

"available": get_balance(from_account)

390

}

391

)

392

393

# Perform transfer

394

return {"status": "success", "transaction_id": "TXN123"}

395

```