Question
In Kotlin, how can I handle multiple exception types for the same try block?
For example, I tried syntax like this:
try {
// code that may throw exceptions
} catch (ex: MyException1, MyException2) {
logger.warn("", ex)
}
and also:
try {
// code that may throw exceptions
} catch (ex: MyException1 | MyException2) {
logger.warn("", ex)
}
Both approaches produce a compilation error such as Unresolved reference: MyException2.
What is the correct way to catch multiple exceptions in Kotlin when the handling logic is the same?
Short Answer
By the end of this page, you will understand how Kotlin handles exceptions, why Java-style multi-catch syntax does not work in Kotlin, and how to write clean alternatives using multiple catch blocks or a common superclass. You will also see practical patterns for reducing duplicated exception-handling code.
Concept
In Kotlin, a try block can be followed by one or more catch blocks. Each catch block handles one exception type.
Unlike Java, Kotlin does not support multi-catch syntax such as:
catch (e: IOException | SQLException)
or comma-separated exception types.
That means if you want to handle multiple exception types, you usually have two choices:
- Write separate
catchblocks for each exception type. - Catch a common superclass if the exceptions are related and should truly be handled the same way.
This matters because exception handling is about writing code that is both:
- safe enough to recover from failures
- clear enough for other developers to understand
Kotlin keeps exception handling explicit. Each catch block clearly shows which exception is being handled. If several exceptions need the same logic, you can still avoid duplication by calling a shared function from multiple catch blocks.
A very important point: Kotlin exceptions are classes, so catching multiple unrelated exception types in one typed variable declaration is not valid Kotlin syntax.
Mental Model
Think of a try block as a room where different problems might happen.
Each catch block is like a different emergency responder:
- one responder handles fire
- one handles flooding
- one handles electrical issues
In Kotlin, each responder has a single specialty. You cannot write one responder label that says “fire or flood” in the catch declaration itself.
If two emergencies should be handled the same way, you have two practical options:
- send two responders who both follow the same checklist
- create a broader responder category that covers both cases
That is exactly how Kotlin exception handling works.
Syntax and Examples
The normal Kotlin syntax is:
try {
// risky code
} catch (e: SomeException) {
// handle exception
} catch (e: AnotherException) {
// handle another exception
}
Option 1: Use separate catch blocks
try {
riskyOperation()
} catch (e: MyException1) {
logger.warn("Operation failed", e)
} catch (e: MyException2) {
logger.warn("Operation failed", e)
}
This is the most direct Kotlin solution.
Option 2: Extract shared handling logic
If the handling code is identical, move it into a function:
fun logWarning(ex: Exception) {
logger.warn("Operation failed", ex)
}
try {
riskyOperation()
} catch (e: MyException1) {
logWarning(e)
} catch (e: MyException2) {
logWarning(e)
}
This keeps the code readable and avoids duplication.
Option 3: Catch a common superclass
If both exceptions inherit from the same custom base exception:
Step by Step Execution
Consider this example:
class MyException1(message: String) : Exception(message)
class MyException2(message: String) : Exception(message)
fun riskyOperation(type: Int) {
if (type == 1) throw MyException1("First problem")
if (type == 2) throw MyException2("Second problem")
println("Success")
}
fun main() {
try {
riskyOperation(2)
} catch (e: MyException1) {
println("Handled MyException1: ${e.message}")
} catch (e: MyException2) {
println("Handled MyException2: ${e.message}")
}
}
What happens step by step
main()starts.- The
tryblock callsriskyOperation(2). - Inside
riskyOperation, is true.
Real World Use Cases
Handling multiple exception types is common in real applications.
File and network operations
A function might fail because:
- a file does not exist
- a network request times out
- data is malformed
Example:
try {
loadUserData()
} catch (e: FileNotFoundException) {
println("Missing file")
} catch (e: IllegalArgumentException) {
println("Invalid data format")
}
API clients
When calling external services, you may want similar logging for several expected failures:
- authentication error
- validation error
- timeout
Database access
A query may fail because of:
- bad input
- connection issues
- missing records
Separate catch blocks let you decide whether to:
- log the issue
- retry the operation
- return a fallback result
- show a user-friendly message
Data parsing
Parsing user input, JSON, or CSV often throws different exceptions. You may want to log them all but still distinguish them for debugging.
Real Codebase Usage
In real Kotlin projects, developers rarely solve this by trying to force multi-catch syntax. Instead, they use patterns that keep exception handling maintainable.
Pattern 1: Multiple catches with shared helper
fun handleFailure(ex: Exception) {
logger.warn("Request failed", ex)
}
try {
processRequest()
} catch (e: MyException1) {
handleFailure(e)
} catch (e: MyException2) {
handleFailure(e)
}
This is common because it is explicit and avoids repeated code.
Pattern 2: Catch a domain-specific parent exception
open class PaymentException(message: String) : Exception(message)
class CardDeclinedException : PaymentException("Card declined")
class PaymentTimeoutException : PaymentException("Payment timeout")
try {
chargeCard()
} catch (e: PaymentException) {
logger.warn("Payment failed", e)
}
This works well when the exception types belong to the same domain.
Pattern 3: Guard clauses before exceptions happen
Sometimes the best exception handling is preventing exceptions with validation.
Common Mistakes
1. Using Java multi-catch syntax in Kotlin
Broken code:
try {
riskyOperation()
} catch (e: MyException1 | MyException2) {
logger.warn("Failed", e)
}
Why it fails:
- Kotlin does not support
|multi-catch syntax.
Use this instead:
try {
riskyOperation()
} catch (e: MyException1) {
logger.warn("Failed", e)
} catch (e: MyException2) {
logger.warn("Failed", e)
}
2. Trying comma-separated exception types
Broken code:
catch (e: MyException1, MyException2)
Why it fails:
- A Kotlin
catchparameter has one type only.
3. Catching Exception too early
Broken code:
try {
riskyOperation()
} catch (e: Exception) {
println("Something went wrong")
} (e: MyException1) {
println()
}
Comparisons
| Approach | Kotlin Support | Best When | Trade-off |
|---|---|---|---|
Separate catch blocks | Yes | You want explicit handling for each type | Slight repetition |
| Shared helper function | Yes | Handling logic is the same | Still needs multiple catches |
| Catch common superclass | Yes | Exceptions are part of the same hierarchy | Can become too broad if misused |
Catch Exception | Yes | Final fallback at app boundary | May hide unexpected problems |
| Java-style multi-catch with ` | ` | No | Never in Kotlin |
Separate catches vs common superclass
Cheat Sheet
try {
riskyOperation()
} catch (e: MyException1) {
// handle MyException1
} catch (e: MyException2) {
// handle MyException2
}
Rules
- A Kotlin
catchblock handles one type. - Kotlin does not support:
catch (e: A | B)catch (e: A, B)
catchblocks are checked top to bottom.- Put more specific exceptions first.
- Use a shared helper function if multiple catches do the same thing.
- Catch a common superclass only if it makes sense in your domain.
- Avoid catching broad
Exceptionunless you need a real fallback.
Shared-handler pattern
fun logError(e: Exception) {
logger.warn("Failed", e)
}
try {
riskyOperation()
} catch (e: MyException1) {
logError(e)
} catch (e: MyException2) {
logError(e)
}
Common-superclass pattern
FAQ
Can Kotlin catch multiple exceptions in one catch block?
Not with Java-style multi-catch syntax. In Kotlin, one catch block has one declared type.
What should I do if two exceptions need the same handling?
Use two separate catch blocks and call the same helper function, or catch a shared superclass if both exceptions belong to it.
Why does catch (e: A | B) fail in Kotlin?
Because Kotlin does not support the Java multi-catch | syntax.
Can I just catch Exception instead?
Yes, but only if you intentionally want to handle all exceptions the same way. It is often too broad.
In what order should catch blocks be written?
From most specific to most general. Otherwise, broader catches can make specific ones unreachable.
Is catching a superclass always a good idea?
No. It is only a good idea when the grouped exceptions really represent the same kind of failure.
Does Kotlin have checked exceptions like Java?
No. Kotlin does not enforce checked exceptions, but runtime exception handling with try and catch still works normally.
Mini Project
Description
Build a small Kotlin program that simulates loading a user profile. The operation can fail for different reasons, and you want to handle multiple exception types cleanly. This project demonstrates the Kotlin way to deal with several exceptions that share the same logging or recovery behavior.
Goal
Create a Kotlin program that throws different custom exceptions and handles them using separate catch blocks with shared logic.
Requirements
- Create two custom exception classes.
- Write a function that throws one of the exceptions based on input.
- Use a
tryblock to call the function. - Handle both exception types with separate
catchblocks. - Reuse the same helper function to log or print the error.
Keep learning
Related questions
Accessing Kotlin Extension Functions from Java
Learn how Kotlin extension functions are compiled and how to call them correctly from Java with clear examples and common pitfalls.
Allow HTTP and HTTPS in Android 9 Pie with Network Security Configuration
Learn how Android 9 Pie handles cleartext HTTP traffic and how to allow HTTP and HTTPS safely using network security config.
Android AlarmManager Example: Scheduling Tasks with AlarmManager
Learn how to use Android AlarmManager to schedule tasks, set alarms, and handle broadcasts with a simple beginner example.