100 Days of Kotlin Multiplatform

In progress 62 posts October 16, 2026

Contents — page 2 of 3

Day 64A Compose UI test in commonTest runs five times and fails on oneThe clock, the input source and the available fonts differ per target.9 minDay 65Four crash reporters, one shared module, and the traces nobody could readThe reporting SDK is platform code and the crash is in shared code.11 minDay 66A deep link is four platform integrations wearing one URLVerified, registered and delivered differently; parsing is the easy part.10 minDay 67There is no shared way to store a secret, and that is the correct answerKeystore and Keychain hold a key your process cannot read.12 minDay 68An expect declaration cannot carry default arguments, and the error says otherwiseDefaults live on the expect side; the diagnostic points at the actual.10 minDay 69ignoreUnknownKeys is a compatibility policy you are choosing for everyoneStrict parsing is an outage on a new field; lenient is silent data loss on a rename.12 minDay 70Ktor plugin order is not style — it decides what gets retriedInstall auth after retry and a refresh happens per attempt; before, once.12 minDay 71The multipart upload that worked on three enginesStreaming a file body needs a filesystem, and one target has none.10 minDay 72One notification API, four delivery systems that behave differentlyChannels, categories, a service worker and a tray have different rules.10 minDay 73Two Kotlin classes, one Objective-C name, and a header that will not compileObjective-C has no namespaces, so two same-named classes export as one.10 minDay 74Gradle's configuration cache, and the one task that kept invalidating itA task capturing Project at execution time disables it for the whole build.10 minDay 75A golden screenshot is a per-platform artifact, whatever the test saysFont rasterisation differs per renderer, so one reference image cannot hold.10 minDay 76Shared navigation state and the one platform that kills your processA back stack in memory is correct on desktop and loses the user's place on Android.12 minDay 77One shared call, five targets, three different stringsLocale-aware formatting is implemented per platform, and the outputs differ.11 minDay 78The shared analytics event that meant something different on each platformEach SDK truncates names, coerces types and limits parameters differently.11 minDay 79Two feature modules that needed each other, and the type that fixed itA direct dependency between siblings is a cycle waiting for the third one.10 minDay 80There is no shared permission API, and the lifecycles disagreeAndroid can be asked twice; iOS once; the browser needs a gesture.11 minDay 81Preferences on five targets: what each one actually persists toFour stores with different durability, size limits and clearing behaviour.11 minDay 82R8 stripped a reflective call that only the shared module madeShrinking runs on one target, so a reflection path ships broken there.10 minDay 83Room compiles for KMP and still needs a driver per targetThe DAO is shared and the connection is not.11 minDay 84Remote config defaults that disagreed, and the feature that shipped twiceThe fetched value is shared and the fallback is per platform.12 minDay 85shareIn's replay count is a product decision, not a tuning knobreplay = 1 re-delivers the last value to every new collector.10 minDay 86A SQLDelight migration is a contract with every installed versionMigrations run forward from whatever version the device holds.12 minDay 87A Kotlin crash on iOS arrives without a usable stack traceThe dSYM for the shared framework is produced by Gradle and uploaded by nobody.10 minDay 88@MainActor and Dispatchers.Main are two different promisesBoth mean the main thread and neither knows about the other.11 min