or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

engine-configuration.mderror-handling.mdfetch-api-types.mdhttp-engine.mdindex.mdrequest-configuration.md

error-handling.mddocs/

0

# Error Handling

1

2

JavaScript-specific error handling with wrapped native JavaScript errors for debugging and error reporting. The Ktor Client JS provides specialized error classes to handle JavaScript runtime errors consistently across different platforms.

3

4

## Capabilities

5

6

### JsError Class

7

8

Wrapper class for JavaScript error objects that provides consistent error handling across browser and Node.js environments.

9

10

```kotlin { .api }

11

/**

12

* Wrapper for javascript error objects.

13

*

14

* @property origin The original JavaScript error object

15

*/

16

class JsError(val origin: dynamic) : Throwable("Error from javascript[$origin].")

17

```

18

19

**Usage Examples:**

20

21

```kotlin

22

import io.ktor.client.*

23

import io.ktor.client.engine.js.*

24

import io.ktor.client.request.*

25

26

val client = HttpClient(Js)

27

28

try {

29

val response = client.get("https://invalid-url")

30

} catch (error: JsError) {

31

// Access the original JavaScript error

32

println("JavaScript error: ${error.origin}")

33

34

// The error message includes the original error

35

println("Error message: ${error.message}")

36

37

// Can inspect JavaScript error properties

38

val jsError = error.origin

39

console.log("Original JS error:", jsError)

40

}

41

```

42

43

### WASM-JS Error Variant

44

45

For WebAssembly-JavaScript environments, a specialized variant provides type-safe error handling.

46

47

```kotlin { .api }

48

/**

49

* WASM-JS specific wrapper for JavaScript error objects.

50

*

51

* @property origin The original JavaScript error object as JsAny

52

*/

53

class JsError(val origin: JsAny) : Throwable("Error from javascript[$origin].")

54

```

55

56

## Common Error Scenarios

57

58

### Network Errors

59

60

```kotlin

61

import io.ktor.client.*

62

import io.ktor.client.engine.js.*

63

import io.ktor.client.request.*

64

65

val client = HttpClient(Js)

66

67

try {

68

val response = client.get("https://unreachable-server.com")

69

} catch (error: JsError) {

70

// Network-related JavaScript errors

71

when {

72

error.message?.contains("TypeError") == true -> {

73

println("Network error: ${error.origin}")

74

}

75

error.message?.contains("Failed to fetch") == true -> {

76

println("Fetch failed: ${error.origin}")

77

}

78

else -> {

79

println("Unknown network error: ${error.origin}")

80

}

81

}

82

}

83

```

84

85

### CORS Errors

86

87

```kotlin

88

try {

89

val response = client.get("https://cors-restricted-api.com") {

90

fetchOptions {

91

mode = "cors"

92

}

93

}

94

} catch (error: JsError) {

95

// CORS-related errors are wrapped as JsError

96

println("CORS error occurred: ${error.origin}")

97

98

// Original error might contain CORS-specific information

99

val corsError = error.origin

100

console.log("CORS details:", corsError)

101

}

102

```

103

104

### Request Cancellation

105

106

```kotlin

107

import org.w3c.dom.AbortController

108

109

val controller = AbortController()

110

111

try {

112

val response = client.get("https://slow-api.com") {

113

fetchOptions {

114

signal = controller.signal

115

}

116

}

117

} catch (error: JsError) {

118

// Check if error is due to request cancellation

119

val jsError = error.origin

120

if (jsError.name == "AbortError") {

121

println("Request was cancelled")

122

} else {

123

println("Other error: ${error.origin}")

124

}

125

}

126

127

// Cancel the request

128

controller.abort()

129

```

130

131

### Timeout Errors

132

133

```kotlin

134

import io.ktor.client.plugins.*

135

136

val client = HttpClient(Js) {

137

install(HttpTimeout) {

138

requestTimeoutMillis = 5000

139

}

140

}

141

142

try {

143

val response = client.get("https://very-slow-api.com")

144

} catch (timeout: HttpRequestTimeoutException) {

145

// Ktor timeout exception

146

println("Request timed out: ${timeout.message}")

147

} catch (error: JsError) {

148

// JavaScript timeout or other errors

149

println("JavaScript error: ${error.origin}")

150

}

151

```

152

153

## Error Inspection Utilities

154

155

### Examining JavaScript Error Properties

156

157

```kotlin

158

fun inspectJsError(error: JsError) {

159

val jsError = error.origin

160

161

// Common JavaScript error properties

162

val name = jsError.name as? String

163

val message = jsError.message as? String

164

val stack = jsError.stack as? String

165

166

println("Error name: $name")

167

println("Error message: $message")

168

println("Error stack: $stack")

169

170

// Platform-specific properties

171

when {

172

name == "TypeError" -> println("Type error occurred")

173

name == "NetworkError" -> println("Network issue detected")

174

name == "AbortError" -> println("Request was aborted")

175

name == "TimeoutError" -> println("Request timed out")

176

}

177

}

178

179

// Usage

180

try {

181

client.get("https://problematic-url.com")

182

} catch (error: JsError) {

183

inspectJsError(error)

184

}

185

```

186

187

### Logging JavaScript Errors

188

189

```kotlin

190

import io.ktor.client.plugins.logging.*

191

192

val client = HttpClient(Js) {

193

install(Logging) {

194

logger = Logger.DEFAULT

195

level = LogLevel.INFO

196

}

197

}

198

199

// Custom error logging

200

suspend fun safeRequest(url: String): String? {

201

return try {

202

val response = client.get(url)

203

response.bodyAsText()

204

} catch (error: JsError) {

205

// Log the JavaScript error details

206

console.error("JavaScript error in request to $url:", error.origin)

207

208

// Return null or throw custom exception

209

null

210

}

211

}

212

```

213

214

## Error Recovery Patterns

215

216

### Retry with Exponential Backoff

217

218

```kotlin

219

import kotlinx.coroutines.delay

220

import kotlin.random.Random

221

222

suspend fun requestWithRetry(

223

url: String,

224

maxRetries: Int = 3,

225

baseDelayMs: Long = 1000

226

): HttpResponse? {

227

var attempt = 0

228

229

while (attempt < maxRetries) {

230

try {

231

return client.get(url)

232

} catch (error: JsError) {

233

attempt++

234

235

if (attempt >= maxRetries) {

236

println("Max retries exceeded for $url")

237

throw error

238

}

239

240

// Exponential backoff with jitter

241

val delayMs = baseDelayMs * (1L shl attempt) + Random.nextLong(1000)

242

println("Request failed, retrying in ${delayMs}ms (attempt $attempt)")

243

delay(delayMs)

244

}

245

}

246

247

return null

248

}

249

```

250

251

### Fallback Mechanisms

252

253

```kotlin

254

suspend fun requestWithFallback(primaryUrl: String, fallbackUrl: String): HttpResponse {

255

return try {

256

client.get(primaryUrl)

257

} catch (primaryError: JsError) {

258

println("Primary request failed: ${primaryError.origin}")

259

260

try {

261

client.get(fallbackUrl)

262

} catch (fallbackError: JsError) {

263

println("Fallback request also failed: ${fallbackError.origin}")

264

throw fallbackError

265

}

266

}

267

}

268

269

// Usage

270

val response = requestWithFallback(

271

"https://primary-api.com/data",

272

"https://backup-api.com/data"

273

)

274

```

275

276

## Platform-Specific Error Handling

277

278

### Browser-Specific Errors

279

280

```kotlin

281

fun handleBrowserErrors(error: JsError) {

282

val jsError = error.origin

283

284

when (jsError.name) {

285

"SecurityError" -> {

286

println("Security policy violation (CORS, mixed content, etc.)")

287

}

288

"NetworkError" -> {

289

println("Network connectivity issue")

290

}

291

"QuotaExceededError" -> {

292

println("Storage quota exceeded")

293

}

294

else -> {

295

println("Other browser error: ${jsError.name}")

296

}

297

}

298

}

299

```

300

301

### Node.js-Specific Errors

302

303

```kotlin

304

fun handleNodeErrors(error: JsError) {

305

val jsError = error.origin

306

val code = jsError.code as? String

307

308

when (code) {

309

"ENOTFOUND" -> {

310

println("DNS resolution failed")

311

}

312

"ECONNREFUSED" -> {

313

println("Connection refused by server")

314

}

315

"ETIMEDOUT" -> {

316

println("Connection timed out")

317

}

318

"ECONNRESET" -> {

319

println("Connection reset by peer")

320

}

321

else -> {

322

println("Node.js error: $code - ${jsError.message}")

323

}

324

}

325

}

326

```

327

328

### Universal Error Handler

329

330

```kotlin

331

fun handleUniversalError(error: JsError) {

332

val jsError = error.origin

333

val name = jsError.name as? String

334

val message = jsError.message as? String

335

336

// Log all error details

337

console.log("Full error object:", jsError)

338

339

// Handle common patterns

340

when {

341

name == "AbortError" -> println("Request was cancelled")

342

message?.contains("Failed to fetch") == true -> println("Network request failed")

343

message?.contains("CORS") == true -> println("CORS policy violation")

344

name == "TypeError" && message?.contains("NetworkError") == true -> {

345

println("Network error (possibly offline)")

346

}

347

else -> {

348

println("Unhandled JavaScript error: $name - $message")

349

}

350

}

351

}

352

```

353

354

## Best Practices

355

356

1. **Always Wrap HTTP Calls**: Use try-catch blocks around HTTP requests to handle `JsError` exceptions

357

358

2. **Inspect Original Errors**: Access the `origin` property to get detailed JavaScript error information

359

360

3. **Platform Detection**: Handle browser vs Node.js specific error patterns differently

361

362

4. **Error Logging**: Log JavaScript errors to external services for debugging production issues

363

364

5. **Graceful Degradation**: Implement fallback mechanisms for network failures

365

366

6. **User-Friendly Messages**: Convert technical JavaScript errors into user-understandable messages