or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

application-setup.mdcomponents.mddependency-injection.mderror-handling.mdindex.mdmodules-and-definitions.mdqualifiers-parameters.mdscoping.md

error-handling.mddocs/

0

# Error Handling

1

2

This document covers the comprehensive exception system in Koin Core, helping you understand and handle dependency injection failures effectively.

3

4

## Overview

5

6

Koin provides specific exception types for different failure scenarios, enabling precise error handling and debugging. The exception system covers:

7

- **Resolution failures** - When dependencies cannot be found or created

8

- **Scope failures** - When scope operations fail or scopes are misused

9

- **Configuration failures** - When module or application setup goes wrong

10

- **Parameter failures** - When parameter passing or resolution fails

11

12

Understanding these exceptions helps you build robust applications with proper error recovery and meaningful error messages.

13

14

## Exception Hierarchy

15

16

All Koin exceptions extend from standard Kotlin/Java `Exception` class:

17

18

```kotlin { .api }

19

// Base class (standard Kotlin)

20

open class Exception : Throwable

21

22

// Koin-specific exceptions (all in org.koin.core.error package)

23

class NoDefinitionFoundException(msg: String) : Exception(msg)

24

class InstanceCreationException(msg: String, parent: Exception) : Exception(msg, parent)

25

class ClosedScopeException(msg: String) : Exception(msg)

26

// ... and others

27

```

28

29

## Resolution Failures

30

31

### NoDefinitionFoundException

32

33

Thrown when a requested dependency cannot be found in any loaded module.

34

35

```kotlin { .api }

36

class NoDefinitionFoundException(msg: String) : Exception(msg)

37

```

38

39

#### Common Causes

40

41

```kotlin

42

val emptyModule = module {

43

// No UserService definition

44

}

45

46

val koin = koinApplication { modules(emptyModule) }.koin

47

48

try {

49

val service: UserService = koin.get() // NoDefinitionFoundException!

50

} catch (e: NoDefinitionFoundException) {

51

println("Service not found: ${e.message}")

52

// Handle missing dependency

53

}

54

```

55

56

#### Prevention and Handling

57

58

```kotlin

59

// Prevention - ensure all dependencies are defined

60

val completeModule = module {

61

single<UserService> { UserService(get()) }

62

single<UserRepository> { UserRepository() }

63

}

64

65

// Handling - use nullable variants

66

val koin = koinApplication { modules(emptyModule) }.koin

67

68

val optionalService: UserService? = koin.getOrNull()

69

if (optionalService == null) {

70

println("UserService not available, using fallback")

71

// Use fallback implementation

72

}

73

```

74

75

#### Qualified Dependency Issues

76

77

```kotlin

78

val qualifiedModule = module {

79

single<ApiService>(named("v1")) { ApiServiceV1() }

80

}

81

82

val koin = koinApplication { modules(qualifiedModule) }.koin

83

84

try {

85

// Wrong qualifier - will throw NoDefinitionFoundException

86

val service: ApiService = koin.get(named("v2"))

87

} catch (e: NoDefinitionFoundException) {

88

// Fallback to v1 or handle error

89

val fallbackService: ApiService = koin.get(named("v1"))

90

}

91

```

92

93

### InstanceCreationException

94

95

Thrown when a definition exists but instance creation fails due to errors in the definition lambda.

96

97

```kotlin { .api }

98

class InstanceCreationException(msg: String, parent: Exception) : Exception(msg, parent)

99

```

100

101

#### Common Scenarios

102

103

```kotlin

104

val problematicModule = module {

105

single<DatabaseService> {

106

// This will throw during creation

107

throw RuntimeException("Database connection failed")

108

}

109

110

factory<FileService> { params ->

111

val path: String = params.get()

112

if (!File(path).exists()) {

113

throw IllegalArgumentException("File not found: $path")

114

}

115

FileService(path)

116

}

117

}

118

119

val koin = koinApplication { modules(problematicModule) }.koin

120

121

try {

122

val dbService: DatabaseService = koin.get()

123

} catch (e: InstanceCreationException) {

124

println("Failed to create DatabaseService: ${e.message}")

125

println("Root cause: ${e.cause}")

126

// Use mock or fallback implementation

127

}

128

```

129

130

#### Handling Creation Failures

131

132

```kotlin

133

class RobustService : KoinComponent {

134

private val primaryService: DataService? by lazy {

135

try {

136

get<DataService>(named("primary"))

137

} catch (e: InstanceCreationException) {

138

logger.warn("Primary service creation failed", e)

139

null

140

}

141

}

142

143

private val fallbackService: DataService by lazy {

144

get<DataService>(named("fallback"))

145

}

146

147

fun processData(): Result {

148

val service = primaryService ?: fallbackService

149

return service.process()

150

}

151

}

152

```

153

154

## Scope Failures

155

156

### ClosedScopeException

157

158

Thrown when attempting to use a scope that has been closed.

159

160

```kotlin { .api }

161

class ClosedScopeException(msg: String) : Exception(msg)

162

```

163

164

#### Typical Usage Scenarios

165

166

```kotlin

167

val scopedModule = module {

168

scope<UserSession> {

169

scoped<SessionData> { SessionData() }

170

}

171

}

172

173

val koin = koinApplication { modules(scopedModule) }.koin

174

val scope = koin.createScope<UserSession>("session-123")

175

176

// Use scope normally

177

val sessionData: SessionData = scope.get()

178

179

// Close scope

180

scope.close()

181

182

try {

183

// This will throw ClosedScopeException

184

val data: SessionData = scope.get()

185

} catch (e: ClosedScopeException) {

186

println("Attempted to use closed scope: ${e.message}")

187

// Create new scope or handle error

188

val newScope = koin.createScope<UserSession>("session-124")

189

}

190

```

191

192

#### Safe Scope Usage

193

194

```kotlin

195

class ScopeManager : KoinComponent {

196

private var currentScope: Scope? = null

197

198

fun getSessionData(): SessionData? {

199

val scope = currentScope

200

return if (scope != null && !scope.closed) {

201

try {

202

scope.get<SessionData>()

203

} catch (e: ClosedScopeException) {

204

currentScope = null

205

null

206

}

207

} else {

208

null

209

}

210

}

211

212

fun createNewSession(): Scope {

213

currentScope?.takeUnless { it.closed }?.close()

214

currentScope = getKoin().createScope<UserSession>(generateSessionId())

215

return currentScope!!

216

}

217

}

218

```

219

220

### ScopeNotCreatedException

221

222

Thrown when trying to access a scope that doesn't exist.

223

224

```kotlin { .api }

225

class ScopeNotCreatedException(msg: String) : Exception(msg)

226

```

227

228

```kotlin

229

val koin = koinApplication { modules(scopedModule) }.koin

230

231

try {

232

// Scope with this ID doesn't exist

233

val scope = koin.getScope("non-existent-scope")

234

} catch (e: ScopeNotCreatedException) {

235

println("Scope not found: ${e.message}")

236

// Create the scope or handle missing scope

237

val newScope = koin.createScope<UserSession>("non-existent-scope")

238

}

239

240

// Safe alternative

241

val safeScope: Scope? = koin.getScopeOrNull("non-existent-scope")

242

if (safeScope == null) {

243

println("Scope doesn't exist, creating new one")

244

// Handle missing scope gracefully

245

}

246

```

247

248

### ScopeAlreadyCreatedException

249

250

Thrown when attempting to create a scope with an ID that already exists.

251

252

```kotlin { .api }

253

class ScopeAlreadyCreatedException(msg: String) : Exception(msg)

254

```

255

256

```kotlin

257

val koin = koinApplication { modules(scopedModule) }.koin

258

259

// Create first scope

260

val scope1 = koin.createScope<UserSession>("duplicate-id")

261

262

try {

263

// This will throw ScopeAlreadyCreatedException

264

val scope2 = koin.createScope<UserSession>("duplicate-id")

265

} catch (e: ScopeAlreadyCreatedException) {

266

println("Scope already exists: ${e.message}")

267

// Use existing scope or generate new ID

268

val existingScope = koin.getScope("duplicate-id")

269

}

270

271

// Safe alternative - get or create pattern

272

val safeScope = koin.getOrCreateScope<UserSession>("duplicate-id")

273

```

274

275

### NoScopeDefFoundException

276

277

Thrown when trying to create a scope for which no scope definition exists.

278

279

```kotlin { .api }

280

class NoScopeDefFoundException(msg: String) : Exception(msg)

281

```

282

283

```kotlin

284

val moduleWithoutScope = module {

285

single<Service> { Service() }

286

// No scope definition for UndefinedScope

287

}

288

289

val koin = koinApplication { modules(moduleWithoutScope) }.koin

290

291

class UndefinedScope

292

293

try {

294

// No scope definition exists for UndefinedScope

295

val scope = koin.createScope<UndefinedScope>("test")

296

} catch (e: NoScopeDefFoundException) {

297

println("No scope definition found: ${e.message}")

298

// Define the scope or use different approach

299

}

300

```

301

302

### MissingScopeValueException

303

304

Thrown when a scoped instance is expected but not found within a scope.

305

306

```kotlin { .api }

307

class MissingScopeValueException(msg: String) : Exception(msg)

308

```

309

310

## Parameter Failures

311

312

### NoParameterFoundException

313

314

Thrown when a definition expects parameters that are not provided.

315

316

```kotlin { .api }

317

class NoParameterFoundException(msg: String) : Exception(msg)

318

```

319

320

```kotlin

321

val parameterModule = module {

322

factory<DatabaseConnection> { params ->

323

val host: String = params.get() // Expects String parameter

324

val port: Int = params.get() // Expects Int parameter

325

DatabaseConnection(host, port)

326

}

327

}

328

329

val koin = koinApplication { modules(parameterModule) }.koin

330

331

try {

332

// No parameters provided - will throw NoParameterFoundException

333

val connection: DatabaseConnection = koin.get()

334

} catch (e: NoParameterFoundException) {

335

println("Missing parameters: ${e.message}")

336

// Provide required parameters

337

val connection: DatabaseConnection = koin.get {

338

parametersOf("localhost", 5432)

339

}

340

}

341

```

342

343

### DefinitionParameterException

344

345

Thrown when there are parameter type mismatches or parameter access errors.

346

347

```kotlin { .api }

348

class DefinitionParameterException(msg: String) : Exception(msg)

349

```

350

351

```kotlin

352

val typedParameterModule = module {

353

factory<Service> { params ->

354

val config: ServiceConfig = params.get() // Expects ServiceConfig

355

Service(config)

356

}

357

}

358

359

val koin = koinApplication { modules(typedParameterModule) }.koin

360

361

try {

362

// Wrong parameter type - will throw DefinitionParameterException

363

val service: Service = koin.get {

364

parametersOf("wrong-type") // String instead of ServiceConfig

365

}

366

} catch (e: DefinitionParameterException) {

367

println("Parameter type error: ${e.message}")

368

// Provide correct parameter type

369

val service: Service = koin.get {

370

parametersOf(ServiceConfig("correct"))

371

}

372

}

373

```

374

375

## Configuration Failures

376

377

### DefinitionOverrideException

378

379

Thrown when attempting to override a definition when overrides are not allowed.

380

381

```kotlin { .api }

382

class DefinitionOverrideException(msg: String) : Exception(msg)

383

```

384

385

```kotlin

386

val firstModule = module {

387

single<Service> { ServiceImpl1() }

388

}

389

390

val secondModule = module {

391

single<Service> { ServiceImpl2() } // Same type, no qualifier

392

}

393

394

try {

395

val koin = koinApplication {

396

allowOverride(false) // Overrides disabled

397

modules(firstModule, secondModule)

398

}.koin

399

} catch (e: DefinitionOverrideException) {

400

println("Definition override not allowed: ${e.message}")

401

402

// Solutions:

403

// 1. Enable overrides

404

val koinWithOverrides = koinApplication {

405

allowOverride(true)

406

modules(firstModule, secondModule)

407

}.koin

408

409

// 2. Use qualifiers

410

val qualifiedModule = module {

411

single<Service>(named("impl1")) { ServiceImpl1() }

412

single<Service>(named("impl2")) { ServiceImpl2() }

413

}

414

}

415

```

416

417

### KoinApplicationAlreadyStartedException

418

419

Thrown when trying to start a Koin application that's already started (in global context scenarios).

420

421

```kotlin { .api }

422

class KoinApplicationAlreadyStartedException(msg: String) : Exception(msg)

423

```

424

425

### MissingPropertyException

426

427

Thrown when a required property is not found.

428

429

```kotlin { .api }

430

class MissingPropertyException(msg: String) : Exception(msg)

431

```

432

433

```kotlin

434

val propertyModule = module {

435

single<DatabaseConfig> {

436

val host = getProperty<String>("db.host") // Required property

437

val port = getProperty<Int>("db.port")

438

DatabaseConfig(host, port)

439

}

440

}

441

442

val koin = koinApplication {

443

modules(propertyModule)

444

// Properties not set

445

}.koin

446

447

try {

448

val config: DatabaseConfig = koin.get()

449

} catch (e: MissingPropertyException) {

450

println("Missing property: ${e.message}")

451

}

452

453

// Provide properties

454

val koinWithProps = koinApplication {

455

properties(mapOf(

456

"db.host" to "localhost",

457

"db.port" to 5432

458

))

459

modules(propertyModule)

460

}.koin

461

```

462

463

### NoPropertyFileFoundException

464

465

Thrown when a specified property file cannot be found.

466

467

```kotlin { .api }

468

class NoPropertyFileFoundException(msg: String) : Exception(msg)

469

```

470

471

## Error Handling Strategies

472

473

### 1. Graceful Degradation

474

475

```kotlin

476

class ResilientService : KoinComponent {

477

private val primaryCache: Cache? = try {

478

get<Cache>(named("redis"))

479

} catch (e: NoDefinitionFoundException) {

480

logger.warn("Redis cache not available, using in-memory cache")

481

null

482

}

483

484

private val fallbackCache: Cache by lazy { get<Cache>(named("memory")) }

485

486

fun getCache(): Cache = primaryCache ?: fallbackCache

487

}

488

```

489

490

### 2. Retry Mechanisms

491

492

```kotlin

493

class RetryingComponent : KoinComponent {

494

fun getServiceWithRetry(maxAttempts: Int = 3): Service {

495

repeat(maxAttempts) { attempt ->

496

try {

497

return get<Service>()

498

} catch (e: InstanceCreationException) {

499

if (attempt == maxAttempts - 1) throw e

500

logger.warn("Service creation failed (attempt ${attempt + 1}), retrying...")

501

Thread.sleep(1000 * (attempt + 1)) // Exponential backoff

502

}

503

}

504

throw IllegalStateException("Should not reach here")

505

}

506

}

507

```

508

509

### 3. Circuit Breaker Pattern

510

511

```kotlin

512

class CircuitBreakerComponent : KoinComponent {

513

private var failureCount = 0

514

private var lastFailureTime = 0L

515

private val circuitBreakerTimeout = 30_000L // 30 seconds

516

private val failureThreshold = 3

517

518

fun getServiceSafely(): Service? {

519

if (isCircuitOpen()) {

520

logger.warn("Circuit breaker open, service unavailable")

521

return null

522

}

523

524

return try {

525

val service: Service = get()

526

resetCircuitBreaker()

527

service

528

} catch (e: Exception) {

529

recordFailure()

530

logger.error("Service access failed", e)

531

null

532

}

533

}

534

535

private fun isCircuitOpen(): Boolean {

536

return failureCount >= failureThreshold &&

537

(System.currentTimeMillis() - lastFailureTime) < circuitBreakerTimeout

538

}

539

540

private fun recordFailure() {

541

failureCount++

542

lastFailureTime = System.currentTimeMillis()

543

}

544

545

private fun resetCircuitBreaker() {

546

failureCount = 0

547

lastFailureTime = 0L

548

}

549

}

550

```

551

552

### 4. Error Context Collection

553

554

```kotlin

555

class DiagnosticHelper : KoinComponent {

556

fun diagnoseInjectionFailure(type: KClass<*>, qualifier: Qualifier? = null): String {

557

val koin = getKoin()

558

559

return buildString {

560

appendLine("Dependency Injection Diagnostic Report")

561

appendLine("Type: ${type.qualifiedName}")

562

appendLine("Qualifier: ${qualifier?.value ?: "None"}")

563

appendLine()

564

565

// Check if any modules are loaded

566

val moduleCount = koin.instanceRegistry.size()

567

appendLine("Loaded definitions: $moduleCount")

568

569

if (moduleCount == 0) {

570

appendLine("❌ No modules loaded! Check your application setup.")

571

return@buildString

572

}

573

574

// Check for similar types

575

appendLine("Available similar types:")

576

// Implementation would scan registry for similar types

577

578

// Check for scope issues

579

if (qualifier != null) {

580

appendLine("Checking qualified definitions...")

581

// Implementation would check for qualifier matches

582

}

583

}

584

}

585

}

586

```

587

588

## Best Practices

589

590

### 1. Use Nullable Variants for Optional Dependencies

591

592

```kotlin

593

// Good - graceful handling of optional dependencies

594

val optionalService: OptionalService? = koin.getOrNull()

595

596

// Avoid - throwing exceptions for optional features

597

try {

598

val service: OptionalService = koin.get()

599

} catch (e: NoDefinitionFoundException) {

600

// Optional service not available

601

}

602

```

603

604

### 2. Validate Critical Dependencies Early

605

606

```kotlin

607

class ApplicationStartup : KoinComponent {

608

fun validateCriticalDependencies() {

609

val criticalServices = listOf(

610

DatabaseService::class,

611

ConfigService::class,

612

SecurityService::class

613

)

614

615

criticalServices.forEach { serviceClass ->

616

try {

617

getKoin().get(serviceClass, null, null)

618

logger.info("✅ ${serviceClass.simpleName} available")

619

} catch (e: NoDefinitionFoundException) {

620

logger.error("❌ Critical service ${serviceClass.simpleName} missing")

621

throw IllegalStateException("Application cannot start without ${serviceClass.simpleName}", e)

622

}

623

}

624

}

625

}

626

```

627

628

### 3. Scope Lifecycle Management

629

630

```kotlin

631

class SafeScopeComponent : KoinScopeComponent {

632

override val scope: Scope by lazy { createScope() }

633

634

fun cleanup() {

635

try {

636

if (!scope.closed) {

637

scope.close()

638

}

639

} catch (e: ClosedScopeException) {

640

// Scope already closed, ignore

641

logger.debug("Scope already closed during cleanup")

642

}

643

}

644

}

645

```

646

647

### 4. Comprehensive Error Logging

648

649

```kotlin

650

class ErrorLoggingComponent : KoinComponent {

651

fun safeGet<T : Any>(

652

type: KClass<T>,

653

qualifier: Qualifier? = null,

654

parameters: ParametersDefinition? = null

655

): T? {

656

return try {

657

getKoin().get(type, qualifier, parameters)

658

} catch (e: NoDefinitionFoundException) {

659

logger.warn("Definition not found for ${type.simpleName} with qualifier $qualifier")

660

null

661

} catch (e: InstanceCreationException) {

662

logger.error("Failed to create instance of ${type.simpleName}", e)

663

null

664

} catch (e: Exception) {

665

logger.error("Unexpected error resolving ${type.simpleName}", e)

666

null

667

}

668

}

669

}

670

```

671

672

Understanding and properly handling Koin exceptions enables you to build robust applications that gracefully handle dependency injection failures and provide meaningful feedback for debugging and monitoring.