|
| 1 | +--- |
| 2 | +name: kotlin-debugging-unresolved-reference-file-clash |
| 3 | +description: > |
| 4 | + Diagnoses and fixes Kotlin JVM "Unresolved reference" compilation errors |
| 5 | + caused by file facade class name clashes. Use when you encounter "Unresolved |
| 6 | + reference" or "can't resolve" errors in a Kotlin JVM or Kotlin Multiplatform |
| 7 | + project where dependencies appear correct, especially after adding, moving, |
| 8 | + or renaming Kotlin files with top-level declarations. |
| 9 | +license: Apache-2.0 |
| 10 | +metadata: |
| 11 | + author: huanshankeji |
| 12 | + version: "1.0.0" |
| 13 | +--- |
| 14 | + |
| 15 | +# Debugging "Unresolved reference" errors caused by Kotlin file facade clashes |
| 16 | + |
| 17 | +## Background: Kotlin file facades on JVM |
| 18 | + |
| 19 | +When a Kotlin file contains top-level declarations (functions, properties, or |
| 20 | +type aliases), the Kotlin/JVM compiler generates a **file facade** class in the |
| 21 | +output bytecode. The facade class is named `<FileName>Kt` (e.g., `Utils.kt` |
| 22 | +produces `UtilsKt.class`) and is placed in the package declared in the file. |
| 23 | + |
| 24 | +If two Kotlin files with the **same file name** and the **same package** end up |
| 25 | +on the same compilation classpath — even if they reside in different source |
| 26 | +directories, source sets, or modules — their generated file facade classes |
| 27 | +**clash**. Instead of a clear "duplicate class" message, the Kotlin compiler |
| 28 | +often reports **misleading "Unresolved reference"** errors on symbols that are |
| 29 | +actually defined correctly. This makes the root cause difficult to identify. |
| 30 | + |
| 31 | +## When to use |
| 32 | + |
| 33 | +Apply this debugging procedure when **all** of the following are true: |
| 34 | + |
| 35 | +1. The compiler reports `Unresolved reference: <symbol>` or similar "can't |
| 36 | + resolve" errors. |
| 37 | +2. The referenced symbol **does** exist in the source code with correct |
| 38 | + visibility and is in the expected dependency. |
| 39 | +3. Project dependencies and imports **look correct** — no obvious missing |
| 40 | + dependency, typo, or visibility issue. |
| 41 | + |
| 42 | +These errors frequently occur after: |
| 43 | + |
| 44 | +- Adding a new Kotlin file that happens to share a name and package with an |
| 45 | + existing file in another source set or module. |
| 46 | +- Moving or renaming files across source sets (e.g., `commonMain` → |
| 47 | + `jvmMain` in Kotlin Multiplatform) without cleaning up the old location. |
| 48 | +- Refactoring that introduces files with common names (e.g., `Icons.kt`, |
| 49 | + `Utils.kt`, `Extensions.kt`) in the same package across modules. |
| 50 | + |
| 51 | +## Diagnostic steps |
| 52 | + |
| 53 | +### Step 1: Search for duplicate file names in the same package |
| 54 | + |
| 55 | +Search the project for Kotlin source files (`.kt`) that share the **same file |
| 56 | +name** and have the **same `package` declaration**. Pay special attention to |
| 57 | +files across different source roots or source sets that are compiled together |
| 58 | +for the same target (e.g., `src/main/kotlin` and another source directory both |
| 59 | +feeding into a JVM compilation). |
| 60 | + |
| 61 | +```bash |
| 62 | +# Example: find all files named "Icons.kt" in the project |
| 63 | +find . -name "Icons.kt" -type f |
| 64 | +``` |
| 65 | + |
| 66 | +Then compare the `package` declarations in each result. If two or more files |
| 67 | +share the same file name and the same package, you have found the clash. |
| 68 | + |
| 69 | +### Step 2: Verify the clash is the root cause |
| 70 | + |
| 71 | +Temporarily rename one of the clashing files (e.g., `Icons.kt` → |
| 72 | +`Icons2.kt`) and rebuild. If the "Unresolved reference" errors disappear, the |
| 73 | +file facade clash was the root cause. |
| 74 | + |
| 75 | +### Step 3: Apply a fix |
| 76 | + |
| 77 | +Choose one of the following fixes: |
| 78 | + |
| 79 | +#### Option A: Rename the file (recommended) |
| 80 | + |
| 81 | +Rename one of the clashing files to a unique name. This is the simplest and |
| 82 | +most reliable fix. |
| 83 | + |
| 84 | +``` |
| 85 | +# Before (clash) |
| 86 | +moduleA/src/main/kotlin/com/example/Icons.kt |
| 87 | +moduleB/src/main/kotlin/com/example/Icons.kt |
| 88 | +
|
| 89 | +# After (fixed) |
| 90 | +moduleA/src/main/kotlin/com/example/Icons.kt |
| 91 | +moduleB/src/main/kotlin/com/example/PlatformIcons.kt |
| 92 | +``` |
| 93 | + |
| 94 | +#### Option B: Change the package |
| 95 | + |
| 96 | +Move one of the files to a different package so the fully qualified facade |
| 97 | +class names differ. |
| 98 | + |
| 99 | +#### Option C: Use `@file:JvmName` (advanced) |
| 100 | + |
| 101 | +If renaming the file is undesirable, annotate one of the files with |
| 102 | +`@file:JvmName` to give its facade class a different JVM name: |
| 103 | + |
| 104 | +```kotlin |
| 105 | +@file:JvmName("PlatformIcons") |
| 106 | + |
| 107 | +package com.example |
| 108 | + |
| 109 | +// top-level declarations... |
| 110 | +``` |
| 111 | + |
| 112 | +This changes the generated class from `IconsKt.class` to |
| 113 | +`PlatformIcons.class`, resolving the clash. Note that this only affects the |
| 114 | +JVM facade name; Kotlin callers are unaffected. |
| 115 | + |
| 116 | +### Step 4: Clean and rebuild |
| 117 | + |
| 118 | +After applying the fix, perform a clean build to ensure no stale class files |
| 119 | +remain: |
| 120 | + |
| 121 | +```bash |
| 122 | +./gradlew clean build |
| 123 | +``` |
| 124 | + |
| 125 | +## Common scenarios |
| 126 | + |
| 127 | +### Kotlin Multiplatform projects |
| 128 | + |
| 129 | +In Kotlin Multiplatform projects, `commonMain`, `jvmMain`, and other source |
| 130 | +sets are compiled together for JVM targets. A file `Utils.kt` with package |
| 131 | +`com.example` in `commonMain` and another `Utils.kt` with the same package in |
| 132 | +`jvmMain` will clash. A conventional solution here is to rename the |
| 133 | +platform-specific file with a platform suffix, e.g., `Utils.jvm.kt`. |
| 134 | + |
| 135 | +### Multi-module Gradle projects |
| 136 | + |
| 137 | +When module A depends on module B and both contain a file with the same name |
| 138 | +and package containing top-level declarations, the file facades collide on the |
| 139 | +classpath. |
| 140 | + |
| 141 | +### After adding or moving files |
| 142 | + |
| 143 | +AI coding agents and developers frequently trigger this when adding new files |
| 144 | +with common names (e.g., `Icons.kt`, `Extensions.kt`, `Helpers.kt`) without |
| 145 | +checking whether a same-named file already exists in the same package elsewhere |
| 146 | +in the project. |
| 147 | + |
| 148 | +## Guardrails |
| 149 | + |
| 150 | +- Do **not** assume the error is a missing dependency or import if the symbol |
| 151 | + clearly exists in the source. |
| 152 | +- Do **not** add redundant dependencies or imports to try to fix the error |
| 153 | + without first checking for file clashes. |
| 154 | +- Before creating a new Kotlin file with top-level declarations, search the |
| 155 | + project for existing files with the same name in the same package. |
| 156 | + |
| 157 | +## References |
| 158 | + |
| 159 | +- [Kotlin documentation: Packages and imports](https://kotlinlang.org/docs/packages.html) |
| 160 | +- [Kotlin documentation: Java interop — Package-level functions](https://kotlinlang.org/docs/java-to-kotlin-interop.html#package-level-functions) |
| 161 | +- [KT-83413: Misleading "Unresolved reference" errors caused by file facade class name clashes](https://youtrack.jetbrains.com/issue/KT-83413) |
0 commit comments