Kotlin Integer Overflow for Coding Interviews: The Complete Guide

- Kotlin integer overflow is silent:
Int.MAX_VALUE + 1wraps toInt.MIN_VALUEwith no exception and no compile warning. - Int is 32-bit (~2.1 × 10^9 max) and Kotlin's default numeric type; the compiler will not widen it for you.
- Binary search midpoint is the most common interview bug: use
left + (right - left) / 2, never(left + right) / 2. .toLong()on one operand before any large multiply widens the entire expression automatically; you only need to call it once.- Declare loop accumulators as
0Lso the sum stays Long from the first iteration, not just after it overflows. - Modular arithmetic trap: even with Long,
a * b % MODcan overflow when both factors approach 10^9; reduce each factor before multiplying. Math.addExactthrowsArithmeticExceptionon overflow and is the correct tool when the problem asks you to detect it.
You're solving a LeetCode medium. Constraints say n can reach 10^9. You sum two indices, run your algorithm, and submit. Wrong answer. The kind that makes you stare at your code like it personally offended you. You add a debug print and the output is a negative number. That's Kotlin integer overflow, and it happens with no warning, no exception, and no stack trace. Just vibes and a wrong answer.
This guide covers every number type Kotlin gives you for interview work, where overflow silently strikes, and the patterns that prevent it.
Every Number Type You'll Actually Use
Kotlin has six built-in numeric types. In practice, three do the work:
| Type | Width | Range | When to use |
|---|---|---|---|
Int | 32-bit | -2,147,483,648 to 2,147,483,647 (~2.1 × 10^9) | Default: indices, small counts |
Long | 64-bit | ~-9.2 × 10^18 to ~9.2 × 10^18 | Sums, products, anything that could exceed 2 × 10^9 |
BigInteger | Arbitrary | No limit | Exact factorial, large combinations, modular exponentiation |
Short (16-bit) and Byte (8-bit) exist but almost never appear in interview code. Double handles floating-point geometry but introduces its own precision trap.
Int is what Kotlin infers by default. Long is what you reach for when constraints touch 10^9.
A literal like 2147483647 infers as Int. The moment you need more room, you have to say so explicitly, because the compiler will not widen for you.
Overflow Is Silent. That's the Whole Problem.
Add 1 to Int.MAX_VALUE in Kotlin:
println(Int.MAX_VALUE + 1) // -2147483648
No exception. No compile warning. The result wraps to Int.MIN_VALUE: Kotlin inherits two's complement arithmetic from the JVM, and the bit pattern rolls over like a car odometer hitting 999,999.
This is the same behavior as Java. If you've been burned by Java's silent overflow, Kotlin gives you no extra protection. If you're coming from Python, where integers are arbitrarily large and you've never had to think about this, congratulations: this is your welcoming committee.
The silence is what makes this dangerous. Your code runs, produces a wrong answer, and the failure mode looks exactly like a logic bug rather than a type issue. You'll spend 10 minutes re-checking your algorithm before you notice the number in your debug output is somehow negative.
You can verify the boundary yourself:
println(Int.MAX_VALUE) // 2147483647 println(Int.MAX_VALUE + 1) // -2147483648 ← wraps println(Long.MAX_VALUE) // 9223372036854775807 println(Long.MAX_VALUE + 1) // -9223372036854775808 ← Long wraps too, much later

Debugging a wrong answer when the bug is a type mismatch, not your algorithm.
Three Places Overflow Kills Your Interview Code
1. Summing two large values
The constraint says 1 ≤ nums[i] ≤ 10^9. You add two elements:
val total = nums[i] + nums[j] // both are Int, could reach 2 × 10^9 → overflow
Int.MAX_VALUE is ~2.1 × 10^9. Two elements each at 10^9 already push 2 × 10^9, right at the limit. Accumulate across more values and you're over.
The fix is to widen before you add, not after:
val total = nums[i].toLong() + nums[j] // one toLong() widens the whole expression
Once one operand is Long, Kotlin promotes the other automatically. You don't need to call .toLong() on both.
2. The binary search midpoint
This is the most famous interview overflow. You have a binary search with left and right as Int:
val mid = (left + right) / 2 // wrong: sum can overflow before the division
If both bounds are large, left + right wraps negative before dividing. The safe form avoids the large intermediate:
val mid = left + (right - left) / 2 // subtraction stays small
right - left is always a valid non-negative difference. Some engineers prefer the explicit cast:
val mid = ((left.toLong() + right) / 2).toInt()
Either form is correct. The wrong form (left + right) / 2 is a documented bug in older Java standard library code, and interviewers know it. They will spot it even on problems where the test inputs don't trigger it, because demonstrating awareness of the boundary is part of the rubric.
For more on binary search correctness, see Your Binary Search Has an Off-by-One Bug. Prove Me Wrong..
3. Multiplying indices or counts
Triangular numbers, area calculations, and combinatorics all multiply values that individually fit in Int but whose product does not:
val n = 100_000 val pairs = n * (n - 1) / 2 // n * (n - 1) ≈ 10^10 → overflows Int silently
The fix: promote before you multiply.
val pairs = n.toLong() * (n - 1) / 2
Multiplication overflow is sneakier than addition overflow because the gap between "looks fine" and "explodes" is larger. The last Int-safe value for n * n is n = 46_340 (46,340² = 2,147,395,600). One higher: 46,341² wraps.
Four Patterns for Safe Arithmetic
Pattern 1: L suffix on literals
Force a Long computation by making the first constant a Long literal:
val result = 1_000_000_000L * n // literal is Long; n is promoted automatically
Useful for constants. Less useful when values come from function parameters inferred as Int.
Pattern 2: .toLong() on one operand
The most common interview pattern:
val result = a.toLong() + b // b promoted automatically val result = a.toLong() * b * c // all three multiplied as Long
Put .toLong() on the first operand. Everything downstream in the expression widens automatically. This is the pattern to drill until it's reflex.
Pattern 3: Declare accumulator as Long from the start
When accumulating in a loop, set the type upfront:
var sum = 0L // Long from the start for (x in nums) { sum += x // x (Int) is promoted automatically }
Declaring var sum = 0 and then doing sum += x keeps everything in Int until something overflows. Declaring 0L sidesteps the problem entirely.
Pattern 4: Math.addExact when overflow should be an error
If a problem asks you to detect overflow (several LeetCode problems do), Kotlin has access to Java's exact arithmetic:
import java.lang.Math try { val result = Math.addExact(a, b) // throws ArithmeticException on overflow val product = Math.multiplyExact(a, b) // same } catch (e: ArithmeticException) { // overflow detected, handle accordingly }
subtractExact and toIntExact (throws if a Long doesn't fit in Int) round out the family. These are niche in interviews but are the right answer when the problem is specifically about detecting overflow. For the Java-side context on this, see Java Integer Overflow: Patterns, Pitfalls, and Safe Code.
When Long Still Isn't Enough: BigInteger
Long handles values up to ~9.2 × 10^18. That covers almost every interview constraint. When a problem asks for exact factorial, exact Catalan numbers, or large modular exponentiation without a modulus, Long runs out.
Kotlin exposes java.math.BigInteger directly:
import java.math.BigInteger fun factorial(n: Int): BigInteger { var result = BigInteger.ONE for (i in 2..n) { result = result.multiply(BigInteger.valueOf(i.toLong())) } return result } println(factorial(20)) // 2432902008176640000 println(factorial(50)) // 30414093201713378043612608166979581188299763898377856000000000000
There's also a convenience extension:
val big = 12345.toBigInteger() val product = big * 67890.toBigInteger() // operator overloading works
BigInteger arithmetic is slower than primitive arithmetic. For interview problems this rarely matters: numbers that require BigInteger are too large to store any other way. The slowdown only bites if you're running millions of BigInteger operations in a hot loop, which is not a typical interview pattern.
The Modular Arithmetic Trap Inside Long
One more Kotlin-specific detail deserves its own callout. Counting problems often reduce results mod 10^9+7. Even when you're working modulo a prime, intermediate products can overflow Long if both factors are close to 10^9:
val MOD = 1_000_000_007L val a = 999_999_999L val b = 999_999_999L println(a * b % MOD) // wrong: a * b overflows Long before the mod println(a % MOD * (b % MOD) % MOD) // correct: products stay below 10^18
Long.MAX_VALUE is ~9.2 × 10^18. Two values each near 10^9 multiply to ~10^18, right at the edge. The safe pattern reduces each factor to [0, MOD) before multiplying. This trips up a surprising number of otherwise-correct DP solutions. See Kotlin Coding Interview Gotchas for related footguns.
The conceptual background on two's complement wrapping is covered in What Is Integer Overflow and Underflow? if you want to understand the bit-level mechanism.
When to Use What
| Situation | What to do |
|---|---|
| Index arithmetic, arrays ≤ 10^6 elements | Int is fine |
| n ≤ 10^9 and you multiply two inputs | .toLong() before the multiply |
| Binary search midpoint | left + (right - left) / 2 |
| Accumulating sum of Int values | Declare accumulator as 0L |
| Exact factorial or large combinations | BigInteger |
| Detecting overflow as a condition | Math.addExact with try-catch |
| Modular arithmetic with large factors | Reduce each factor mod MOD before multiplying |
Checking if a Long fits back in Int | Math.toIntExact(longValue) |
Build the Muscle Now, Not During the Interview
You won't have time to reason through type widening when you're 20 minutes into a hard problem. The patterns above need to be automatic: .toLong() before the first multiply, 0L for any accumulator, left + (right - left) / 2 in every binary search. That kind of precision under pressure is exactly what voice-based mock interviews at SpaceComplexity train you to hold. The rubric scores implementation correctness, not just whether your high-level approach was right.