or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

authentication.mdclient-side-caching.mdclustering.mdcommands-operations.mdconnection-management.mdcore-clients.mdexceptions.mdindex.mdmodules.mdparameters.mdpubsub.mdtransactions-pipelining.md

exceptions.mddocs/

0

# Exception Handling

1

2

This document covers the comprehensive exception hierarchy in Jedis for robust error handling, including connection exceptions, cluster-specific exceptions, authentication failures, and best practices for error recovery.

3

4

## Exception Hierarchy

5

6

### Base Exception Classes

7

8

#### JedisException

9

10

Root exception class for all Jedis-specific exceptions.

11

12

```java { .api }

13

public class JedisException extends RuntimeException {

14

/**

15

* Creates exception with message

16

* @param message Error message

17

*/

18

public JedisException(String message);

19

20

/**

21

* Creates exception with message and cause

22

* @param message Error message

23

* @param cause Underlying cause

24

*/

25

public JedisException(String message, Throwable cause);

26

27

/**

28

* Creates exception with cause

29

* @param cause Underlying cause

30

*/

31

public JedisException(Throwable cause);

32

33

/**

34

* Gets error message

35

* @return Exception message

36

*/

37

@Override

38

public String getMessage();

39

40

/**

41

* Gets underlying cause

42

* @return Exception cause

43

*/

44

@Override

45

public Throwable getCause();

46

}

47

```

48

49

#### JedisDataException

50

51

Exception for Redis server errors and data-related issues.

52

53

```java { .api }

54

public class JedisDataException extends JedisException {

55

/**

56

* Creates data exception with message

57

* @param message Error message from Redis server

58

*/

59

public JedisDataException(String message);

60

61

/**

62

* Creates data exception with message and cause

63

* @param message Error message

64

* @param cause Underlying cause

65

*/

66

public JedisDataException(String message, Throwable cause);

67

}

68

```

69

70

## Connection Exceptions

71

72

### JedisConnectionException

73

74

Exception for connection-related failures.

75

76

```java { .api }

77

public class JedisConnectionException extends JedisException {

78

/**

79

* Creates connection exception

80

* @param message Connection error message

81

*/

82

public JedisConnectionException(String message);

83

84

/**

85

* Creates connection exception with cause

86

* @param message Error message

87

* @param cause Network or I/O exception cause

88

*/

89

public JedisConnectionException(String message, Throwable cause);

90

91

/**

92

* Creates connection exception from cause

93

* @param cause Network exception

94

*/

95

public JedisConnectionException(Throwable cause);

96

}

97

```

98

99

#### Usage Example

100

101

```java

102

public void handleConnectionErrors() {

103

Jedis jedis = null;

104

try {

105

jedis = new Jedis("redis.example.com", 6379);

106

jedis.set("key", "value");

107

108

} catch (JedisConnectionException e) {

109

System.err.println("Connection failed: " + e.getMessage());

110

111

// Check underlying cause

112

Throwable cause = e.getCause();

113

if (cause instanceof SocketTimeoutException) {

114

System.err.println("Connection timed out");

115

} else if (cause instanceof ConnectException) {

116

System.err.println("Cannot reach Redis server");

117

} else if (cause instanceof UnknownHostException) {

118

System.err.println("Invalid Redis hostname");

119

}

120

121

// Implement retry logic

122

retryConnection();

123

124

} finally {

125

if (jedis != null) {

126

try {

127

jedis.close();

128

} catch (Exception e) {

129

System.err.println("Error closing connection: " + e.getMessage());

130

}

131

}

132

}

133

}

134

135

private void retryConnection() {

136

int maxRetries = 3;

137

int retryDelay = 1000; // 1 second

138

139

for (int i = 0; i < maxRetries; i++) {

140

try {

141

Thread.sleep(retryDelay * (i + 1)); // Exponential backoff

142

143

Jedis jedis = new Jedis("redis.example.com", 6379);

144

jedis.ping(); // Test connection

145

jedis.close();

146

147

System.out.println("Connection restored");

148

return;

149

150

} catch (JedisConnectionException | InterruptedException e) {

151

System.err.println("Retry " + (i + 1) + " failed: " + e.getMessage());

152

}

153

}

154

155

System.err.println("All retry attempts failed");

156

}

157

```

158

159

## Cluster Exceptions

160

161

### JedisClusterException

162

163

General Redis Cluster operation exceptions.

164

165

```java { .api }

166

public class JedisClusterException extends JedisException {

167

/**

168

* Creates cluster exception

169

* @param message Error message

170

*/

171

public JedisClusterException(String message);

172

173

/**

174

* Creates cluster exception with cause

175

* @param message Error message

176

* @param cause Exception cause

177

*/

178

public JedisClusterException(String message, Throwable cause);

179

180

/**

181

* Creates cluster exception from cause

182

* @param cause Exception cause

183

*/

184

public JedisClusterException(Throwable cause);

185

}

186

```

187

188

### JedisClusterOperationException

189

190

Exceptions specific to cluster operations.

191

192

```java { .api }

193

public class JedisClusterOperationException extends JedisClusterException {

194

/**

195

* Creates cluster operation exception

196

* @param message Operation error message

197

*/

198

public JedisClusterOperationException(String message);

199

200

/**

201

* Creates cluster operation exception with cause

202

* @param message Error message

203

* @param cause Exception cause

204

*/

205

public JedisClusterOperationException(String message, Throwable cause);

206

}

207

```

208

209

### Cluster Redirection Exceptions

210

211

#### JedisRedirectionException

212

213

Base class for Redis Cluster redirection responses.

214

215

```java { .api }

216

public abstract class JedisRedirectionException extends JedisException {

217

/**

218

* Creates redirection exception

219

* @param message Redirection message

220

* @param targetNode Target node for redirection

221

* @param slot Cluster slot number

222

*/

223

public JedisRedirectionException(String message, HostAndPort targetNode, int slot);

224

225

/**

226

* Gets target node for redirection

227

* @return Target Redis cluster node

228

*/

229

public HostAndPort getTargetNode();

230

231

/**

232

* Gets cluster slot number

233

* @return Slot number (0-16383)

234

*/

235

public int getSlot();

236

}

237

```

238

239

#### JedisMovedDataException

240

241

Exception for Redis Cluster MOVED responses.

242

243

```java { .api }

244

public class JedisMovedDataException extends JedisRedirectionException {

245

/**

246

* Creates MOVED exception

247

* @param message MOVED response message

248

* @param targetNode Node that owns the slot

249

* @param slot Cluster slot number

250

*/

251

public JedisMovedDataException(String message, HostAndPort targetNode, int slot);

252

}

253

```

254

255

#### JedisAskDataException

256

257

Exception for Redis Cluster ASK responses.

258

259

```java { .api }

260

public class JedisAskDataException extends JedisRedirectionException {

261

/**

262

* Creates ASK exception

263

* @param message ASK response message

264

* @param targetNode Node to ask for data

265

* @param slot Cluster slot number

266

*/

267

public JedisAskDataException(String message, HostAndPort targetNode, int slot);

268

}

269

```

270

271

#### Cluster Exception Handling Example

272

273

```java

274

public class ClusterErrorHandler {

275

private static final int MAX_REDIRECTIONS = 5;

276

277

public String getWithRedirection(JedisCluster cluster, String key) {

278

return executeWithRedirection(() -> cluster.get(key));

279

}

280

281

public <T> T executeWithRedirection(Supplier<T> operation) {

282

int redirections = 0;

283

284

while (redirections < MAX_REDIRECTIONS) {

285

try {

286

return operation.get();

287

288

} catch (JedisMovedDataException e) {

289

// Cluster topology changed, refresh slot mapping

290

System.out.println("MOVED: Slot " + e.getSlot() +

291

" moved to " + e.getTargetNode());

292

293

// JedisCluster handles this automatically, but we log it

294

redirections++;

295

296

if (redirections >= MAX_REDIRECTIONS) {

297

throw new JedisClusterOperationException(

298

"Too many MOVED redirections", e);

299

}

300

301

} catch (JedisAskDataException e) {

302

// Temporary redirection during slot migration

303

System.out.println("ASK: Slot " + e.getSlot() +

304

" temporarily at " + e.getTargetNode());

305

306

// JedisCluster handles this automatically

307

redirections++;

308

309

if (redirections >= MAX_REDIRECTIONS) {

310

throw new JedisClusterOperationException(

311

"Too many ASK redirections", e);

312

}

313

314

} catch (JedisClusterException e) {

315

// General cluster error

316

System.err.println("Cluster operation failed: " + e.getMessage());

317

318

if (e.getCause() instanceof JedisConnectionException) {

319

// Node unavailable, cluster may retry automatically

320

throw new JedisClusterOperationException(

321

"Cluster node unavailable", e);

322

}

323

324

throw e;

325

}

326

}

327

328

throw new JedisClusterOperationException("Max redirections exceeded");

329

}

330

}

331

```

332

333

## Server State Exceptions

334

335

### JedisBusyException

336

337

Exception when Redis server is busy.

338

339

```java { .api }

340

public class JedisBusyException extends JedisDataException {

341

/**

342

* Creates busy exception

343

* @param message Server busy message

344

*/

345

public JedisBusyException(String message);

346

}

347

```

348

349

### JedisNoScriptException

350

351

Exception when Lua script is not found in server cache.

352

353

```java { .api }

354

public class JedisNoScriptException extends JedisDataException {

355

/**

356

* Creates no-script exception

357

* @param message Script not found message

358

*/

359

public JedisNoScriptException(String message);

360

361

/**

362

* Gets script SHA that wasn't found

363

* @return Script SHA hash

364

*/

365

public String getScriptSha();

366

}

367

```

368

369

#### Server State Exception Handling

370

371

```java

372

public class ScriptManager {

373

private final Map<String, String> scriptShas = new ConcurrentHashMap<>();

374

375

public Object executeScript(Jedis jedis, String script, List<String> keys,

376

List<String> args) {

377

String sha = scriptShas.computeIfAbsent(script,

378

s -> jedis.scriptLoad(s));

379

380

try {

381

return jedis.evalsha(sha, keys, args);

382

383

} catch (JedisNoScriptException e) {

384

System.out.println("Script not in cache, loading: " + e.getScriptSha());

385

386

// Reload script and retry

387

String newSha = jedis.scriptLoad(script);

388

scriptShas.put(script, newSha);

389

390

return jedis.evalsha(newSha, keys, args);

391

392

} catch (JedisBusyException e) {

393

System.err.println("Redis server busy: " + e.getMessage());

394

395

// Wait and retry once

396

try {

397

Thread.sleep(100);

398

return jedis.evalsha(sha, keys, args);

399

} catch (InterruptedException ie) {

400

Thread.currentThread().interrupt();

401

throw new JedisException("Script execution interrupted", ie);

402

}

403

}

404

}

405

}

406

```

407

408

## Security Exceptions

409

410

### Authentication Exceptions

411

412

#### JedisAccessControlException

413

414

Exception for Redis ACL (Access Control List) violations.

415

416

```java { .api }

417

public class JedisAccessControlException extends JedisDataException {

418

/**

419

* Creates ACL exception

420

* @param message Access control error message

421

*/

422

public JedisAccessControlException(String message);

423

}

424

```

425

426

#### JedisAuthenticationException

427

428

Exception for authentication failures.

429

430

```java { .api }

431

public class JedisAuthenticationException extends JedisException {

432

/**

433

* Creates authentication exception

434

* @param message Authentication error message

435

*/

436

public JedisAuthenticationException(String message);

437

438

/**

439

* Creates authentication exception with cause

440

* @param message Error message

441

* @param cause Exception cause

442

*/

443

public JedisAuthenticationException(String message, Throwable cause);

444

}

445

```

446

447

#### Security Exception Handling

448

449

```java

450

public class SecureRedisClient {

451

private final String username;

452

private final String password;

453

454

public SecureRedisClient(String username, String password) {

455

this.username = username;

456

this.password = password;

457

}

458

459

public Jedis createSecureConnection(String host, int port) {

460

try {

461

Jedis jedis = new Jedis(host, port);

462

463

// Authenticate

464

if (username != null && password != null) {

465

jedis.auth(username, password);

466

} else if (password != null) {

467

jedis.auth(password);

468

}

469

470

// Test connection

471

jedis.ping();

472

return jedis;

473

474

} catch (JedisAuthenticationException e) {

475

System.err.println("Authentication failed: " + e.getMessage());

476

throw new SecurityException("Cannot authenticate to Redis", e);

477

478

} catch (JedisAccessControlException e) {

479

System.err.println("Access denied: " + e.getMessage());

480

481

if (e.getMessage().contains("NOPERM")) {

482

System.err.println("User lacks required permissions");

483

} else if (e.getMessage().contains("WRONGPASS")) {

484

System.err.println("Invalid password");

485

}

486

487

throw new SecurityException("Access control violation", e);

488

489

} catch (JedisConnectionException e) {

490

System.err.println("Connection failed during authentication: " + e.getMessage());

491

throw e;

492

}

493

}

494

495

public <T> T executeSecureOperation(String host, int port,

496

Function<Jedis, T> operation) {

497

Jedis jedis = null;

498

try {

499

jedis = createSecureConnection(host, port);

500

return operation.apply(jedis);

501

502

} catch (JedisAccessControlException e) {

503

System.err.println("Operation denied by ACL: " + e.getMessage());

504

505

// Could implement fallback to read-only operations

506

if (e.getMessage().contains("WRITE")) {

507

System.out.println("Attempting read-only fallback");

508

// Implement read-only version

509

}

510

511

throw e;

512

513

} finally {

514

if (jedis != null) {

515

jedis.close();

516

}

517

}

518

}

519

}

520

```

521

522

## Validation Exceptions

523

524

### JedisValidationException

525

526

Exception for input validation errors.

527

528

```java { .api }

529

public class JedisValidationException extends JedisException {

530

/**

531

* Creates validation exception

532

* @param message Validation error message

533

*/

534

public JedisValidationException(String message);

535

}

536

```

537

538

### InvalidURIException

539

540

Exception for malformed Redis connection URIs.

541

542

```java { .api }

543

public class InvalidURIException extends JedisException {

544

/**

545

* Creates invalid URI exception

546

* @param message URI error message

547

*/

548

public InvalidURIException(String message);

549

550

/**

551

* Creates invalid URI exception with cause

552

* @param message Error message

553

* @param cause URI parsing exception

554

*/

555

public InvalidURIException(String message, Throwable cause);

556

}

557

```

558

559

## Cache and Broadcast Exceptions

560

561

### JedisCacheException

562

563

Exception for client-side cache operations.

564

565

```java { .api }

566

public class JedisCacheException extends JedisException {

567

/**

568

* Creates cache exception

569

* @param message Cache error message

570

*/

571

public JedisCacheException(String message);

572

573

/**

574

* Creates cache exception with cause

575

* @param message Error message

576

* @param cause Cache operation cause

577

*/

578

public JedisCacheException(String message, Throwable cause);

579

}

580

```

581

582

### JedisBroadcastException

583

584

Exception for broadcast operations across multiple Redis instances.

585

586

```java { .api }

587

public class JedisBroadcastException extends JedisException {

588

/**

589

* Creates broadcast exception

590

* @param message Broadcast error message

591

*/

592

public JedisBroadcastException(String message);

593

594

/**

595

* Creates broadcast exception with partial results

596

* @param message Error message

597

* @param cause Exception cause

598

*/

599

public JedisBroadcastException(String message, Throwable cause);

600

}

601

```

602

603

## Exception Handling Best Practices

604

605

### Comprehensive Error Handler

606

607

```java

608

public class RobustJedisClient {

609

private static final Logger logger = LoggerFactory.getLogger(RobustJedisClient.class);

610

private final JedisPool pool;

611

private final int maxRetries;

612

613

public RobustJedisClient(JedisPool pool, int maxRetries) {

614

this.pool = pool;

615

this.maxRetries = maxRetries;

616

}

617

618

public <T> T executeWithRetry(Function<Jedis, T> operation) {

619

int attempts = 0;

620

JedisException lastException = null;

621

622

while (attempts < maxRetries) {

623

try (Jedis jedis = pool.getResource()) {

624

return operation.apply(jedis);

625

626

} catch (JedisConnectionException e) {

627

lastException = e;

628

attempts++;

629

630

logger.warn("Connection attempt {} failed: {}", attempts, e.getMessage());

631

632

if (attempts < maxRetries) {

633

waitBeforeRetry(attempts);

634

}

635

636

} catch (JedisBusyException e) {

637

lastException = e;

638

attempts++;

639

640

logger.warn("Server busy on attempt {}: {}", attempts, e.getMessage());

641

642

if (attempts < maxRetries) {

643

waitBeforeRetry(attempts);

644

}

645

646

} catch (JedisDataException e) {

647

// Data exceptions usually don't benefit from retry

648

logger.error("Data operation failed: {}", e.getMessage());

649

throw e;

650

651

} catch (JedisAuthenticationException e) {

652

// Authentication errors shouldn't be retried

653

logger.error("Authentication failed: {}", e.getMessage());

654

throw e;

655

656

} catch (JedisValidationException e) {

657

// Validation errors shouldn't be retried

658

logger.error("Validation failed: {}", e.getMessage());

659

throw e;

660

661

} catch (JedisException e) {

662

// Generic Jedis exception

663

lastException = e;

664

attempts++;

665

666

logger.warn("Operation attempt {} failed: {}", attempts, e.getMessage());

667

668

if (attempts < maxRetries) {

669

waitBeforeRetry(attempts);

670

}

671

}

672

}

673

674

logger.error("All {} retry attempts failed", maxRetries);

675

throw new JedisException("Operation failed after " + maxRetries + " attempts",

676

lastException);

677

}

678

679

private void waitBeforeRetry(int attempt) {

680

try {

681

// Exponential backoff with jitter

682

long delay = Math.min(1000 * (1L << attempt), 10000); // Max 10 seconds

683

long jitter = (long) (Math.random() * 1000); // Up to 1 second jitter

684

685

Thread.sleep(delay + jitter);

686

} catch (InterruptedException e) {

687

Thread.currentThread().interrupt();

688

throw new JedisException("Retry interrupted", e);

689

}

690

}

691

}

692

```

693

694

### Circuit Breaker Pattern

695

696

```java

697

public class CircuitBreakerJedisClient {

698

private enum State { CLOSED, OPEN, HALF_OPEN }

699

700

private volatile State state = State.CLOSED;

701

private volatile int failures = 0;

702

private volatile long lastFailureTime = 0;

703

private final int failureThreshold;

704

private final long timeout;

705

706

public CircuitBreakerJedisClient(int failureThreshold, long timeout) {

707

this.failureThreshold = failureThreshold;

708

this.timeout = timeout;

709

}

710

711

public <T> T execute(Function<Jedis, T> operation) {

712

if (state == State.OPEN) {

713

if (System.currentTimeMillis() - lastFailureTime > timeout) {

714

state = State.HALF_OPEN;

715

} else {

716

throw new JedisException("Circuit breaker is OPEN");

717

}

718

}

719

720

try (Jedis jedis = getJedis()) {

721

T result = operation.apply(jedis);

722

onSuccess();

723

return result;

724

725

} catch (JedisException e) {

726

onFailure();

727

throw e;

728

}

729

}

730

731

private synchronized void onSuccess() {

732

failures = 0;

733

state = State.CLOSED;

734

}

735

736

private synchronized void onFailure() {

737

failures++;

738

lastFailureTime = System.currentTimeMillis();

739

740

if (failures >= failureThreshold) {

741

state = State.OPEN;

742

}

743

}

744

745

private Jedis getJedis() {

746

// Get Jedis instance from pool or create new one

747

return new Jedis("localhost", 6379);

748

}

749

}

750

```

751

752

### Exception Logging and Monitoring

753

754

```java

755

public class MonitoredJedisClient {

756

private static final Logger logger = LoggerFactory.getLogger(MonitoredJedisClient.class);

757

private final MeterRegistry meterRegistry;

758

759

public MonitoredJedisClient(MeterRegistry meterRegistry) {

760

this.meterRegistry = meterRegistry;

761

}

762

763

public <T> T executeWithMonitoring(String operationName, Function<Jedis, T> operation) {

764

Timer.Sample sample = Timer.start(meterRegistry);

765

766

try (Jedis jedis = new Jedis("localhost", 6379)) {

767

T result = operation.apply(jedis);

768

769

meterRegistry.counter("jedis.operations.success", "operation", operationName)

770

.increment();

771

772

return result;

773

774

} catch (JedisConnectionException e) {

775

logAndCount("connection_error", operationName, e);

776

throw e;

777

778

} catch (JedisClusterException e) {

779

logAndCount("cluster_error", operationName, e);

780

throw e;

781

782

} catch (JedisAuthenticationException e) {

783

logAndCount("auth_error", operationName, e);

784

throw e;

785

786

} catch (JedisDataException e) {

787

logAndCount("data_error", operationName, e);

788

throw e;

789

790

} catch (JedisException e) {

791

logAndCount("generic_error", operationName, e);

792

throw e;

793

794

} finally {

795

sample.stop(Timer.builder("jedis.operations.duration")

796

.tag("operation", operationName)

797

.register(meterRegistry));

798

}

799

}

800

801

private void logAndCount(String errorType, String operationName, JedisException e) {

802

logger.error("Jedis {} error in operation {}: {}",

803

errorType, operationName, e.getMessage(), e);

804

805

meterRegistry.counter("jedis.operations.error",

806

"operation", operationName,

807

"error_type", errorType)

808

.increment();

809

}

810

}

811

```

812

813

The Jedis exception hierarchy provides comprehensive error handling capabilities for all Redis deployment scenarios. Proper exception handling is crucial for building resilient applications that can gracefully handle network issues, cluster topology changes, authentication problems, and server errors.