or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

api-groups.mdclient-configuration.mdcore-resources.mdcustom-resources.mdexception-handling.mdindex.mdpod-operations.mdutilities.mdwatch-informers.md

exception-handling.mddocs/

0

# Exception Handling

1

2

The Fabric8 Kubernetes Client provides a comprehensive exception hierarchy for handling various error conditions that can occur during Kubernetes API operations. Understanding these exceptions is crucial for building robust applications.

3

4

## Core Exception Classes

5

6

### KubernetesClientException

7

8

Main exception class for all Kubernetes client operations.

9

10

```java { .api }

11

public class KubernetesClientException extends RuntimeException {

12

// Constructors

13

public KubernetesClientException(String message);

14

public KubernetesClientException(String message, Throwable cause);

15

public KubernetesClientException(Throwable cause);

16

public KubernetesClientException(Status status);

17

public KubernetesClientException(String message, int code, Status status);

18

19

// Status information

20

public Status getStatus();

21

public int getCode();

22

public String getFullResourceName();

23

24

// Utility methods

25

public static KubernetesClientException launderThrowable(Throwable cause);

26

public static KubernetesClientException launderThrowable(String message, Throwable cause);

27

}

28

```

29

30

### ResourceNotFoundException

31

32

Exception thrown when a requested resource is not found.

33

34

```java { .api }

35

public class ResourceNotFoundException extends KubernetesClientException {

36

public ResourceNotFoundException(String message);

37

public ResourceNotFoundException(String message, Throwable cause);

38

}

39

```

40

41

### KubernetesClientTimeoutException

42

43

Exception thrown when operations exceed configured timeout values.

44

45

```java { .api }

46

public class KubernetesClientTimeoutException extends KubernetesClientException {

47

public KubernetesClientTimeoutException(String message);

48

public KubernetesClientTimeoutException(String message, long timeout, TimeUnit timeUnit);

49

public KubernetesClientTimeoutException(String message, Throwable cause);

50

51

public long getTimeout();

52

public TimeUnit getTimeUnit();

53

}

54

```

55

56

### WatcherException

57

58

Exception specific to watch operations and informer functionality.

59

60

```java { .api }

61

public class WatcherException extends Exception {

62

public WatcherException(String message);

63

public WatcherException(String message, Throwable cause);

64

public WatcherException(Throwable cause);

65

66

// Conversion methods

67

public KubernetesClientException asClientException();

68

69

// HTTP Gone detection

70

public boolean isHttpGone();

71

}

72

```

73

74

## HTTP Status Code Mapping

75

76

The client maps HTTP status codes to specific exception conditions:

77

78

- **200-299**: Success (no exception)

79

- **400**: Bad Request - Invalid resource definition or parameters

80

- **401**: Unauthorized - Authentication required or failed

81

- **403**: Forbidden - Insufficient permissions for the operation

82

- **404**: Not Found - Resource or endpoint doesn't exist

83

- **409**: Conflict - Resource already exists or version conflict

84

- **410**: Gone - Resource version too old (common in watch operations)

85

- **422**: Unprocessable Entity - Validation errors

86

- **429**: Too Many Requests - Rate limiting

87

- **500**: Internal Server Error - Kubernetes API server error

88

- **503**: Service Unavailable - API server overloaded or maintenance

89

90

## Usage Examples

91

92

### Basic Exception Handling

93

94

```java

95

try {

96

Pod pod = client.pods().withName("my-pod").get();

97

if (pod != null) {

98

System.out.println("Pod found: " + pod.getMetadata().getName());

99

} else {

100

System.out.println("Pod not found (returned null)");

101

}

102

103

} catch (KubernetesClientException e) {

104

System.out.println("Error accessing pod: " + e.getMessage());

105

System.out.println("HTTP status code: " + e.getCode());

106

107

if (e.getStatus() != null) {

108

Status status = e.getStatus();

109

System.out.println("API status: " + status.getStatus());

110

System.out.println("Reason: " + status.getReason());

111

System.out.println("Message: " + status.getMessage());

112

}

113

}

114

```

115

116

### Handling Specific HTTP Status Codes

117

118

```java

119

try {

120

// Try to create a resource

121

ConfigMap configMap = client.configMaps().create(new ConfigMapBuilder()

122

.withNewMetadata()

123

.withName("my-config")

124

.endMetadata()

125

.withData(Map.of("key", "value"))

126

.build());

127

128

} catch (KubernetesClientException e) {

129

switch (e.getCode()) {

130

case 400:

131

System.out.println("Bad request - invalid resource definition: " + e.getMessage());

132

break;

133

case 401:

134

System.out.println("Authentication required: " + e.getMessage());

135

break;

136

case 403:

137

System.out.println("Access denied - insufficient permissions: " + e.getMessage());

138

break;

139

case 409:

140

System.out.println("Resource already exists: " + e.getMessage());

141

// Maybe try to update instead

142

break;

143

case 422:

144

System.out.println("Validation error: " + e.getMessage());

145

if (e.getStatus() != null && e.getStatus().getDetails() != null) {

146

StatusDetails details = e.getStatus().getDetails();

147

if (details.getCauses() != null) {

148

for (StatusCause cause : details.getCauses()) {

149

System.out.println(" Field: " + cause.getField() +

150

", Reason: " + cause.getReason() +

151

", Message: " + cause.getMessage());

152

}

153

}

154

}

155

break;

156

case 429:

157

System.out.println("Rate limited - too many requests: " + e.getMessage());

158

// Implement backoff and retry

159

break;

160

default:

161

System.out.println("Unexpected error (HTTP " + e.getCode() + "): " + e.getMessage());

162

}

163

}

164

```

165

166

### ResourceNotFoundException Handling

167

168

```java

169

// Using require() method that throws ResourceNotFoundException

170

try {

171

Pod pod = client.pods().withName("required-pod").require();

172

// Pod is guaranteed to exist here

173

System.out.println("Required pod found: " + pod.getMetadata().getName());

174

175

} catch (ResourceNotFoundException e) {

176

System.out.println("Required pod not found: " + e.getMessage());

177

// Handle missing resource

178

}

179

180

// Alternative approach with explicit null check

181

Pod pod = client.pods().withName("optional-pod").get();

182

if (pod == null) {

183

System.out.println("Optional pod not found");

184

} else {

185

System.out.println("Optional pod found: " + pod.getMetadata().getName());

186

}

187

```

188

189

### Timeout Exception Handling

190

191

```java

192

try {

193

// Wait for pod to be ready with timeout

194

Pod readyPod = client.pods().withName("slow-starting-pod")

195

.waitUntilReady(2, TimeUnit.MINUTES);

196

197

System.out.println("Pod is ready: " + readyPod.getMetadata().getName());

198

199

} catch (KubernetesClientTimeoutException e) {

200

System.out.println("Timeout waiting for pod to be ready: " + e.getMessage());

201

System.out.println("Timeout was: " + e.getTimeout() + " " + e.getTimeUnit());

202

203

// Check current pod status

204

Pod currentPod = client.pods().withName("slow-starting-pod").get();

205

if (currentPod != null) {

206

PodStatus status = currentPod.getStatus();

207

System.out.println("Current phase: " + status.getPhase());

208

209

if (status.getConditions() != null) {

210

for (PodCondition condition : status.getConditions()) {

211

System.out.println("Condition: " + condition.getType() +

212

" = " + condition.getStatus() +

213

" (" + condition.getReason() + ")");

214

}

215

}

216

}

217

218

} catch (InterruptedException e) {

219

Thread.currentThread().interrupt();

220

System.out.println("Wait interrupted: " + e.getMessage());

221

}

222

```

223

224

### Watch Exception Handling

225

226

```java

227

Watch watch = client.pods().watch(new Watcher<Pod>() {

228

@Override

229

public void eventReceived(Action action, Pod pod) {

230

try {

231

System.out.println(action + ": " + pod.getMetadata().getName());

232

// Process the event

233

processEvent(action, pod);

234

235

} catch (Exception e) {

236

System.err.println("Error processing event: " + e.getMessage());

237

}

238

}

239

240

@Override

241

public void onClose(WatcherException cause) {

242

if (cause != null) {

243

System.out.println("Watch closed with error: " + cause.getMessage());

244

245

if (cause.isHttpGone()) {

246

System.out.println("HTTP 410 Gone - resource version too old");

247

System.out.println("Need to restart watch with fresh resource version");

248

restartWatch();

249

} else {

250

// Other error - convert to client exception for detailed info

251

KubernetesClientException clientException = cause.asClientException();

252

System.out.println("Watch error code: " + clientException.getCode());

253

254

// Decide whether to restart based on error type

255

if (clientException.getCode() >= 500) {

256

System.out.println("Server error - will retry watch");

257

scheduleWatchRetry();

258

} else {

259

System.out.println("Client error - not retrying");

260

}

261

}

262

} else {

263

System.out.println("Watch closed normally");

264

}

265

}

266

});

267

```

268

269

### Exception Chaining and Root Cause Analysis

270

271

```java

272

try {

273

// Complex operation that might have nested exceptions

274

performComplexKubernetesOperation();

275

276

} catch (KubernetesClientException e) {

277

System.out.println("Kubernetes operation failed: " + e.getMessage());

278

279

// Analyze the exception chain

280

Throwable cause = e.getCause();

281

while (cause != null) {

282

System.out.println("Caused by: " + cause.getClass().getSimpleName() +

283

": " + cause.getMessage());

284

cause = cause.getCause();

285

}

286

287

// Use launderThrowable to clean up exception chain

288

KubernetesClientException laundered = KubernetesClientException.launderThrowable(e);

289

System.out.println("Laundered exception: " + laundered.getMessage());

290

}

291

292

private void performComplexKubernetesOperation() {

293

try {

294

// Some operation that might throw various exceptions

295

client.apps().deployments().withName("my-deployment").scale(5);

296

297

} catch (Exception e) {

298

// Wrap and re-throw with context

299

throw KubernetesClientException.launderThrowable("Failed to scale deployment", e);

300

}

301

}

302

```

303

304

### Retry Logic with Exponential Backoff

305

306

```java

307

public <T> T retryOperation(Supplier<T> operation, int maxRetries) {

308

int retries = 0;

309

long delay = 1000; // Start with 1 second

310

311

while (retries < maxRetries) {

312

try {

313

return operation.get();

314

315

} catch (KubernetesClientException e) {

316

retries++;

317

318

// Don't retry on client errors (4xx)

319

if (e.getCode() >= 400 && e.getCode() < 500 && e.getCode() != 429) {

320

throw e;

321

}

322

323

// Don't retry on the last attempt

324

if (retries >= maxRetries) {

325

throw e;

326

}

327

328

System.out.println("Operation failed (attempt " + retries + "/" + maxRetries +

329

"): " + e.getMessage() + ". Retrying in " + delay + "ms");

330

331

try {

332

Thread.sleep(delay);

333

} catch (InterruptedException ie) {

334

Thread.currentThread().interrupt();

335

throw new RuntimeException("Retry interrupted", ie);

336

}

337

338

// Exponential backoff with jitter

339

delay = Math.min(delay * 2 + (long)(Math.random() * 1000), 30000);

340

}

341

}

342

343

throw new RuntimeException("Max retries exceeded");

344

}

345

346

// Usage example

347

try {

348

Pod pod = retryOperation(() ->

349

client.pods().withName("unstable-pod").get(), 3);

350

351

if (pod != null) {

352

System.out.println("Successfully retrieved pod: " + pod.getMetadata().getName());

353

}

354

355

} catch (Exception e) {

356

System.out.println("Failed to retrieve pod after retries: " + e.getMessage());

357

}

358

```

359

360

### Validation Error Handling

361

362

```java

363

try {

364

// Create a pod with invalid configuration

365

Pod invalidPod = client.pods().create(new PodBuilder()

366

.withNewMetadata()

367

.withName("invalid-pod-name-with-underscores_here") // Invalid name

368

.endMetadata()

369

.withNewSpec()

370

.addNewContainer()

371

.withName("app")

372

.withImage("") // Invalid empty image

373

.endContainer()

374

.endSpec()

375

.build());

376

377

} catch (KubernetesClientException e) {

378

if (e.getCode() == 422) { // Unprocessable Entity

379

System.out.println("Validation errors occurred:");

380

381

Status status = e.getStatus();

382

if (status != null && status.getDetails() != null) {

383

StatusDetails details = status.getDetails();

384

385

System.out.println("Resource: " + details.getKind() + "/" + details.getName());

386

387

if (details.getCauses() != null) {

388

for (StatusCause cause : details.getCauses()) {

389

System.out.println(" Field '" + cause.getField() + "': " +

390

cause.getMessage() + " (reason: " + cause.getReason() + ")");

391

}

392

}

393

}

394

} else {

395

System.out.println("Other error: " + e.getMessage());

396

}

397

}

398

```

399

400

### Global Exception Handler

401

402

```java

403

public class KubernetesExceptionHandler {

404

405

public static void handleException(KubernetesClientException e, String operation) {

406

System.err.println("Kubernetes operation failed: " + operation);

407

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

408

System.err.println("HTTP Code: " + e.getCode());

409

410

// Log full resource name if available

411

if (e.getFullResourceName() != null) {

412

System.err.println("Resource: " + e.getFullResourceName());

413

}

414

415

// Log Kubernetes status if available

416

if (e.getStatus() != null) {

417

Status status = e.getStatus();

418

System.err.println("Status: " + status.getStatus());

419

System.err.println("Reason: " + status.getReason());

420

421

if (status.getDetails() != null) {

422

StatusDetails details = status.getDetails();

423

System.err.println("Kind: " + details.getKind());

424

System.err.println("Name: " + details.getName());

425

System.err.println("Group: " + details.getGroup());

426

}

427

}

428

429

// Log stack trace for debugging

430

e.printStackTrace();

431

}

432

433

public static boolean isRetryable(KubernetesClientException e) {

434

int code = e.getCode();

435

436

// Retry on server errors and rate limiting

437

if (code >= 500 || code == 429) {

438

return true;

439

}

440

441

// Retry on network-related errors

442

if (e.getCause() instanceof java.net.SocketTimeoutException ||

443

e.getCause() instanceof java.net.ConnectException) {

444

return true;

445

}

446

447

return false;

448

}

449

}

450

451

// Usage in application

452

try {

453

Pod pod = client.pods().create(newPod);

454

} catch (KubernetesClientException e) {

455

KubernetesExceptionHandler.handleException(e, "create pod");

456

457

if (KubernetesExceptionHandler.isRetryable(e)) {

458

// Implement retry logic

459

scheduleRetry();

460

}

461

}

462

```