Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KSP2: KtInvalidLifetimeOwnerAccessException: Access to invalid KtAlwaysAccessibleLifetimeToken: PSI has changed since creation #1854

Closed
Tracked by #16
ting-yuan opened this issue Apr 24, 2024 · 22 comments · Fixed by r0adkll/kimchi#34 or #2175
Assignees
Labels
bug Something isn't working
Milestone

Comments

@ting-yuan
Copy link
Collaborator

ting-yuan commented Apr 24, 2024

See https://youtrack.jetbrains.com/issue/KT-67158 for test cases.

@ting-yuan ting-yuan added the bug Something isn't working label Apr 24, 2024
@ting-yuan ting-yuan added this to the 2.0 milestone Apr 24, 2024
@ting-yuan
Copy link
Collaborator Author

The keys of androidx.room.compiler.processing.ksp.KspArrayType.Factory.reverseBuiltinArrayLookup are stale. It could be a bug in Room.

@FooIbar
Copy link

FooIbar commented May 22, 2024

Is the Room team aware of this? Didn't find it in the public tracker.

@vRallev
Copy link

vRallev commented Jun 10, 2024

I'm running into the same issue with my processor and another processor. What I'm doing is caching a KSClassDeclaration through multiple rounds and then calling packageName throws this error:

ksp.org.jetbrains.kotlin.analysis.api.lifetime.KtInvalidLifetimeOwnerAccessException: Access to invalid ksp.org.jetbrains.kotlin.analysis.api.lifetime.KtAlwaysAccessibleLifetimeToken@a17dbac: PSI has changed since creation
	at ksp.org.jetbrains.kotlin.analysis.api.fir.utils.ValidityAwareCachedValue.getValue-impl(ValidityAwareCachedValue.kt:33)
	at ksp.org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirNamedClassOrObjectSymbol.getPsi(KtFirNamedClassOrObjectSymbol.kt:36)
	at com.google.devtools.ksp.impl.symbol.kotlin.UtilKt.toContainingFile(util.kt:236)
	at com.google.devtools.ksp.impl.symbol.kotlin.AbstractKSDeclarationImpl$containingFile$2.invoke(AbstractKSDeclarationImpl.kt:77)
	at com.google.devtools.ksp.impl.symbol.kotlin.AbstractKSDeclarationImpl$containingFile$2.invoke(AbstractKSDeclarationImpl.kt:76)
	at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
	at com.google.devtools.ksp.impl.symbol.kotlin.AbstractKSDeclarationImpl.getContainingFile(AbstractKSDeclarationImpl.kt:76)
	at com.google.devtools.ksp.impl.symbol.kotlin.AbstractKSDeclarationImpl$packageName$2.invoke(AbstractKSDeclarationImpl.kt:83)
	at com.google.devtools.ksp.impl.symbol.kotlin.AbstractKSDeclarationImpl$packageName$2.invoke(AbstractKSDeclarationImpl.kt:80)
	at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
	at com.google.devtools.ksp.impl.symbol.kotlin.AbstractKSDeclarationImpl.getPackageName(AbstractKSDeclarationImpl.kt:80)
	at com.amazon.lastmile.app.platform.inject.processor.MergeComponentProcessor.generateComponentInterface(MergeComponentProcessor.kt:91)

To me this seems to be a regression in KSP 2. I tested with 2.0.0-1.0.22 and ksp.useKSP2=true.

I'm running into this issue with another processor that defers processing of symbols to later rounds and caches these symbols. When it's actually processing the symbols the same exception is thrown:

ksp.org.jetbrains.kotlin.analysis.api.lifetime.KtInvalidLifetimeOwnerAccessException: Access to invalid ksp.org.jetbrains.kotlin.analysis.api.lifetime.KtAlwaysAccessibleLifetimeToken@5bf278a3: PSI has changed since creation
	at ksp.org.jetbrains.kotlin.analysis.api.fir.utils.ValidityAwareCachedValue.getValue-impl(ValidityAwareCachedValue.kt:33)
	at ksp.org.jetbrains.kotlin.analysis.api.fir.types.KtFirClassErrorType.getAnnotationsList(KtFirClassErrorType.kt:50)
	at com.google.devtools.ksp.impl.symbol.kotlin.KSTypeImpl$Companion.getCached(KSTypeImpl.kt:40)
	at com.google.devtools.ksp.impl.symbol.kotlin.KSTypeReferenceImpl.resolve(KSTypeReferenceImpl.kt:68)
	at com.google.devtools.ksp.visitor.KSValidateVisitor.visitTypeReference(KSValidateVisitor.kt:57)
	at com.google.devtools.ksp.visitor.KSValidateVisitor.visitTypeReference(KSValidateVisitor.kt:5)
	at com.google.devtools.ksp.impl.symbol.kotlin.KSTypeReferenceImpl.accept(KSTypeReferenceImpl.kt:82)
	at com.google.devtools.ksp.visitor.KSValidateVisitor.visitClassDeclaration(KSValidateVisitor.kt:64)
	at me.tatarka.inject.compiler.ksp.InjectProcessor$validate$1.visitClassDeclaration(InjectProcessor.kt:107)
	at me.tatarka.inject.compiler.ksp.InjectProcessor$validate$1.visitClassDeclaration(InjectProcessor.kt:87)
	at com.google.devtools.ksp.impl.symbol.kotlin.KSClassDeclarationImpl.accept(KSClassDeclarationImpl.kt:175)
	at me.tatarka.inject.compiler.ksp.InjectProcessor.validate(InjectProcessor.kt:86)
	at me.tatarka.inject.compiler.ksp.InjectProcessor.process(InjectProcessor.kt:53)
	at com.google.devtools.ksp.impl.KotlinSymbolProcessing.execute(KotlinSymbolProcessing.kt:533)
	at com.tschuchort.compiletesting.Ksp2PrecursorTool.execute(Ksp2.kt:112)

The kotlin-inject processor caches the deferred classes here.

This happens while running unit tests using https://github.com/ZacSweers/kotlin-compile-testing/releases/tag/0.5.0. This could be related. This happens during normal compilation as well and is not related to the compile testing library.

@neetopia neetopia reopened this Jun 10, 2024
@ting-yuan
Copy link
Collaborator Author

Using elements across rounds is currently unsupported, because generated code may affect the elements. For example, the return type of a function may be an error in round 1 and defined by a class generated in round 2. In KSP1, caching elements across rounds happens to work for some cases but not all. In KSP2, the lifecycle check is more strict and the error is always thrown. This is not a regression.

KSP's deferral mechanism (returning symbols to be deferred from process()) is designed to handle this use case. Please try to use it and let us know if it doesn't serve your use case well.

@vRallev
Copy link

vRallev commented Jun 11, 2024

KSP's deferral mechanism (returning symbols to be deferred from process()) is designed to handle this use case. Please try to use it and let us know if it doesn't serve your use case well.

I'm not sure I understand this sentence. The kotlin-inject processor supports multiple rounds and defers generating files when needed. This creates challenges though. To avoid generating duplicate files, you either must track which were already generated when getting symbols with an annotation, or you get symbols of with the annotation only of the new files of this round. kotlin-inject does the latter and therefore must track the deferred symbols. Even the previous options requires tracking symbols from the previous round.

An alternative is to try generating duplicate files and catch the exception, but that doesn't sound right. I feel like I'm missing something or there's a gap.

My processor is in a similar situation. My workaround for now looks something like this, which only works because I can "reload" or "refresh" the class symbol:

deferredClassesFromPreviousRound.forEach {
    val clazz = resolver.getClassDeclarationByName(it.qualifiedName!!)!!
    generate...(resolver, clazz)
}

But all of this feels wrong.

vRallev added a commit to vRallev/kotlin-inject that referenced this issue Jun 11, 2024
`InjectProcessor` remembers deferred symbols across rounds. KSP (KSP 2 in particular) forbids to cache symbols across rounds and verifies the lifecycle. The fix is trying to get new symbols of the deferred classes each round.

For more details: google/ksp#1854
@evant
Copy link
Contributor

evant commented Jun 11, 2024

Fyi I had asked about this originally when implementing and I told that what I was doing was ok https://kotlinlang.slack.com/archives/C013BA8EQSE/p1635106134012300

@evant
Copy link
Contributor

evant commented Jun 11, 2024

My last comment in that thread still stands

so the part that caught me up wasn't that you needed to return them, but that you need keep track of them yourself for reprocessing. I erroneously thought they'd be given back as new on the next round.

You have to track what you deferred yourself between rounds as you won't get those symbols given back to you which makes it very easy to trip on this issue.

@ting-yuan
Copy link
Collaborator Author

The deferral mechanism is designed around Resolver.getSymbolsWithAnntation. In addition to newly generated files, the coming round also considers deferred symbols in getSymbolsWithAnntation, the implementation of which is literally:

    override fun getSymbolsWithAnnotation(annotationName: String, inDepth: Boolean): Sequence<KSAnnotated> {
        // ...
        return (newSymbols + deferredSymbolsRestored).asSequence().filter(::checkAnnotated)
    }

There are no other ways to access deferred symbols though, so it makes more sense to defer the root elements than others, or at least those with annotation. We should probably have created another API that allows access to all deferred symbols. Before doing that, I'd like to know what you think. Is the current API fit your use case?

@vRallev
Copy link

vRallev commented Jun 11, 2024

From my own testing, the API isn't reliable. In our internal project I see non-deferred symbols from previous rounds popping up again. So I thought this was by design until I checked the documentation yesterday. Any chance this changed recently? I'm not sure if I can isolate the problem, it definitely happens in unit tests.

@ting-yuan
Copy link
Collaborator Author

Would you mind checking if the popped up symbols were (indirectly) from getAllFiles (instead of getNewFiles) or getClassDeclarationByName? which returns / searches all files, processed or not.

@evant
Copy link
Contributor

evant commented Jun 11, 2024

The deferral mechanism is designed around Resolver.getSymbolsWithAnntation

Oh that's good to know, I was using getNewFiles() directly since I know where my annotation may be present I can resolve less of the ast. But that does not include the deferred symbols.

@evant
Copy link
Contributor

evant commented Jun 11, 2024

Before doing that, I'd like to know what you think. Is the current API fit your use case?

Even if I switched I'd think I'd still want to get the deferred symbols directly so I can report errors on the final round in finish().

evant added a commit to evant/kotlin-inject that referenced this issue Jun 11, 2024
Reusing symbols between rounds is not supported and throws an error on
ksp2. Unfortunately this means we need to use `getSymbolsWithAnnotation`
instead of our custom functions as they are currently the only way to
access updated deferred symbols. We still keep a list of the symbol
names so that we can run a final processing pass on the last round.

See google/ksp#1854
evant added a commit to evant/kotlin-inject that referenced this issue Jun 11, 2024
Reusing symbols between rounds is not supported and throws an error on
ksp2. Unfortunately this means we need to use `getSymbolsWithAnnotation`
instead of our custom functions as they are currently the only way to
access updated deferred symbols. We still keep a list of the symbol
names so that we can run a final processing pass on the last round.

See google/ksp#1854
evant added a commit to evant/kotlin-inject that referenced this issue Jun 11, 2024
Reusing symbols between rounds is not supported and throws an error on
ksp2. Unfortunately this means we need to use `getSymbolsWithAnnotation`
instead of our custom functions as they are currently the only way to
access updated deferred symbols. We still keep a list of the symbol
names so that we can run a final processing pass on the last round.

See google/ksp#1854
@evant
Copy link
Contributor

evant commented Jun 11, 2024

Just pushed up https://github.com/evant/kotlin-inject/pull/393/files to fix this. Should show off the trade-offs that are needed with the current api using getSymbolsWithAnnotation and the extra lookups required in finish().

@vRallev
Copy link

vRallev commented Jun 11, 2024

Would you mind checking if the popped up symbols were (indirectly) from getAllFiles (instead of getNewFiles) or getClassDeclarationByName? which returns / searches all files, processed or not.

No, I'm definitely using

fun getSymbolsWithAnnotation(annotationName: String, inDepth: Boolean = false): Sequence<KSAnnotated>

And because of this issue I have to do this:

    fun Resolver.getNewSymbolsWithAnnotation(annotation: KClass<*>): Sequence<KSAnnotated> {
        val newFiles = getNewFiles().toSet()
        return getSymbolsWithAnnotation(annotation)
            .filter { it.containingFile in newFiles }
    }

@evant
Copy link
Contributor

evant commented Jun 11, 2024

@vRallev won't the code you posted filter out the deferred symbols again? Since they may not be from new files for the round.

@vRallev
Copy link

vRallev commented Jun 11, 2024

Yes, currently we track deferred symbols in our processor like you do.

evant added a commit to evant/kotlin-inject that referenced this issue Jun 11, 2024
Don't reuse symbols between rounds

Reusing symbols between rounds is not supported and throws an error on
ksp2. Unfortunately this means we need to use `getSymbolsWithAnnotation`
instead of our custom functions as they are currently the only way to
access updated deferred symbols. We still keep a list of the symbol
names so that we can run a final processing pass on the last round.

See google/ksp#1854
renovate bot added a commit to julioromano/mooviez that referenced this issue Jun 12, 2024
[![Mend
Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com)

This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
|
[me.tatarka.inject:kotlin-inject-runtime](https://togithub.com/evant/kotlin-inject)
| `0.6.3` -> `0.7.1` |
[![age](https://developer.mend.io/api/mc/badges/age/maven/me.tatarka.inject:kotlin-inject-runtime/0.7.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/maven/me.tatarka.inject:kotlin-inject-runtime/0.7.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/maven/me.tatarka.inject:kotlin-inject-runtime/0.6.3/0.7.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/maven/me.tatarka.inject:kotlin-inject-runtime/0.6.3/0.7.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
|
[me.tatarka.inject:kotlin-inject-compiler-ksp](https://togithub.com/evant/kotlin-inject)
| `0.6.3` -> `0.7.1` |
[![age](https://developer.mend.io/api/mc/badges/age/maven/me.tatarka.inject:kotlin-inject-compiler-ksp/0.7.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/maven/me.tatarka.inject:kotlin-inject-compiler-ksp/0.7.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/maven/me.tatarka.inject:kotlin-inject-compiler-ksp/0.6.3/0.7.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/maven/me.tatarka.inject:kotlin-inject-compiler-ksp/0.6.3/0.7.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>evant/kotlin-inject
(me.tatarka.inject:kotlin-inject-runtime)</summary>

###
[`v0.7.1`](https://togithub.com/evant/kotlin-inject/blob/HEAD/CHANGELOG.md#071-2024-06-12)

##### Fixed

-   Removed erroneous `@KmpComponentCreator` annotation.

###
[`v0.7.0`](https://togithub.com/evant/kotlin-inject/blob/HEAD/CHANGELOG.md#070-2024-06-12)

##### Changed

- `@Scope` annotations now take arguments into account. This means for
example, if you have
    ```kotlin
    @&#8203;Scope
    annotation class NamedScope(val value: String)
    ```
then the scope: `@NamedScope("one")` and `@NamedScope("two")` would be
treated as distinct. Previously they were
    treated as the same scope.
- Legacy implicit assisted injection (not using the `@Assisted`
annotation) is now an error.
- The build will now fail if multiple qualifiers are applied in the same
place, instead of picking the first one. This
applies both to the new annotation (see below) and
`javax.inject.Qualifier`. A minor exception is you are allowed to
have one of each type to aid in migration. In that case the
`me.tatarka.inject` one will be chosen.

##### Added

- Added a `me.tatarka.inject.annotations.Qualifier` annotation as an
alternative to using typealias. For example, you
    could do:
    ```kotlin
    @&#8203;Qualifier
    annotation class Named(val value: String) 

    @&#8203;Inject
class MyClass(@&#8203;Named("one") val one: String, @&#8203;Named("two")
val two: String)

    @&#8203;Component
    abstract class MyComponent {
      abstract val myClass: MyClass

      @&#8203;Provides @&#8203;Named("one")
      fun provideOne(): String = "one"

      @&#8203;Provides @&#8203;Named("two")
      fun provideTwo(): String = "two" 
    }
    ```
This behaves the same as `javax.inject.Qualifier` does when you have
`me.tatarka.inject.enableJavaxAnnotations=true`.
- Added a new `@KmpComponentCreate` annotation for nicer multiplatform
support. This allows you to create component
instances from common code when generating platform-specific outputs.
    ```kotlin
    // src/commonMain
    @&#8203;Component
    abstract class MyKmpComponent
     
    @&#8203;KmpComponentCreate
    expect fun createKmp(): MyKmpComponent
    ```
see the new [multiplatform docs](docs/multiplatform.md) for more
details.
- You can now use an `@Inject` annotation on an inner class provided the
outer class can be provided.
    ```kotlin
    @&#8203;Inject class Outer { @&#8203;Inject inner class Inner }

@&#8203;Component abstract class MyComponent { abstract val inner:
Outer.Inner }
    ```

##### Removed

- The KAPT backend is removed, please migrate to KSP if you haven't
already.

##### Fixed

- Fixed cases of invalid code generation
([#&#8203;321](https://togithub.com/evant/kotlin-inject/issues/321),
[#&#8203;337](https://togithub.com/evant/kotlin-inject/issues/337),
[#&#8203;313](https://togithub.com/evant/kotlin-inject/issues/313)).
- Fixed an exception thrown on KSP2 when running multiple rounds
([google/ksp#1854](https://togithub.com/google/ksp/issues/1854)).
- Fixed various issues with handling method overrides in components
([#&#8203;309](https://togithub.com/evant/kotlin-inject/issues/309),
[#&#8203;375](https://togithub.com/evant/kotlin-inject/issues/375))
- Allow scope annotations on both an interface and component
implementation if they are the same scope
([#&#8203;320](https://togithub.com/evant/kotlin-inject/issues/320)).

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about these
updates again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend
Renovate](https://www.mend.io/free-developer-tools/renovate/). View
repository job log
[here](https://developer.mend.io/github/julioromano/mooviez).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNy4zOTMuMCIsInVwZGF0ZWRJblZlciI6IjM3LjM5My4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
r0adkll added a commit to r0adkll/kimchi that referenced this issue Aug 27, 2024
r0adkll added a commit to r0adkll/kimchi that referenced this issue Aug 27, 2024
Added `rank` ordering
Added tests for `@ContributesBinding`
Fixed google/ksp#1854
r0adkll added a commit to r0adkll/kimchi that referenced this issue Sep 4, 2024
Added `rank` ordering
Added tests for `@ContributesBinding`
Fixed google/ksp#1854
r0adkll added a commit to r0adkll/kimchi that referenced this issue Sep 4, 2024
Added `rank` ordering
Added tests for `@ContributesBinding`
Fixed google/ksp#1854
@joffrey-bion
Copy link

joffrey-bion commented Oct 10, 2024

FYI I'm facing this as well when trying to run Koin with KSP2. I'm not 100% sure whether it's the same issue, because the stacktrace is slightly different:

Exception in thread "main" ksp.org.jetbrains.kotlin.analysis.api.lifetime.KaInvalidLifetimeOwnerAccessException: Access to invalid ksp.org.jetbrains.kotlin.analysis.api.platform.lifetime.KotlinAlwaysAccessibleLifetimeToken@8f09a02: PSI has changed since creation
 	at ksp.org.jetbrains.kotlin.analysis.api.fir.annotations.KaFirAnnotationListForDeclaration.iterator(KaFirAnnotationListForDeclaration.kt:107)
 	at com.google.devtools.ksp.impl.symbol.kotlin.UtilKt$annotations$3$1.invoke(util.kt:1032)
 	at com.google.devtools.ksp.impl.symbol.kotlin.UtilKt$annotations$3$1.invoke(util.kt:375)
 	at com.google.devtools.ksp.impl.symbol.kotlin.KSAnnotationImpl$annotationApplication$2.invoke(KSAnnotationImpl.kt:58)
 	at com.google.devtools.ksp.impl.symbol.kotlin.KSAnnotationImpl$annotationApplication$2.invoke(KSAnnotationImpl.kt:57)
 	at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
 	at com.google.devtools.ksp.impl.symbol.kotlin.KSAnnotationImpl.getAnnotationApplication(KSAnnotationImpl.kt:57)
 	at com.google.devtools.ksp.impl.symbol.kotlin.KSAnnotationImpl.access$getAnnotationApplication(KSAnnotationImpl.kt:41)
 	at com.google.devtools.ksp.impl.symbol.kotlin.KSAnnotationImpl$arguments$2.invoke(KSAnnotationImpl.kt:73)
 	at com.google.devtools.ksp.impl.symbol.kotlin.KSAnnotationImpl$arguments$2.invoke(KSAnnotationImpl.kt:72)
 	at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
 	at com.google.devtools.ksp.impl.symbol.kotlin.KSAnnotationImpl.getArguments(KSAnnotationImpl.kt:72)
 	at org.koin.compiler.metadata.AnnotationMetadataKt.includedModules(AnnotationMetadata.kt:81)
 	at org.koin.compiler.scanner.ModuleScanner.getIncludedModules(ModuleScanner.kt:69)
 	at org.koin.compiler.scanner.ModuleScanner.createClassModule(ModuleScanner.kt:32)
 	at org.koin.compiler.scanner.KoinMetaDataScanner.scanClassModules(KoinMetaDataScanner.kt:130)
 	at org.koin.compiler.scanner.KoinMetaDataScanner.scanKoinModules(KoinMetaDataScanner.kt:76)
 	at org.koin.compiler.BuilderProcessor.process(BuilderProcessor.kt:57)
 	at com.google.devtools.ksp.impl.KotlinSymbolProcessing.execute(KotlinSymbolProcessing.kt:540)
 	at com.google.devtools.ksp.cmdline.KSPJvmMainKt.runWithArgs(KSPJvmMain.kt:45)
 	at com.google.devtools.ksp.cmdline.KSPJvmMain$Companion.main(KSPJvmMain.kt:20)
 	at com.google.devtools.ksp.cmdline.KSPJvmMain.main(KSPJvmMain.kt)

@technoir42
Copy link
Contributor

technoir42 commented Oct 24, 2024

I'm facing this issue when using the latest version of Glide or Room with ksp.useKSP2=true. KSP1 doesn't have this issue.

> Task :android:library:kspDebugKotlin FAILED
e: [ksp] ksp.org.jetbrains.kotlin.analysis.api.lifetime.KaInvalidLifetimeOwnerAccessException: Access to invalid ksp.org.jetbrains.kotlin.analysis.api.platform.lifetime.KotlinAlwaysAccessibleLifetimeToken@73164e9c: PSI has changed since creation

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':android:library:kspDebugKotlin'.
> A failure occurred while executing com.google.devtools.ksp.gradle.KspAAWorkerAction
   > Access to invalid ksp.org.jetbrains.kotlin.analysis.api.platform.lifetime.KotlinAlwaysAccessibleLifetimeToken@73164e9c: PSI has changed since creation
Caused by: ksp.org.jetbrains.kotlin.analysis.api.lifetime.KaInvalidLifetimeOwnerAccessException: Access to invalid ksp.org.jetbrains.kotlin.analysis.api.platform.lifetime.KotlinAlwaysAccessibleLifetimeToken@73164e9c: PSI has changed since creation
	at ksp.org.jetbrains.kotlin.analysis.api.fir.symbols.KaFirFileSymbol.getPsi(KaFirFileSymbol.kt:58)
	at com.google.devtools.ksp.impl.symbol.kotlin.KSFileImpl.getPsi(KSFileImpl.kt:44)
	at com.google.devtools.ksp.impl.symbol.kotlin.KSFileImpl.access$getPsi(KSFileImpl.kt:38)
	at com.google.devtools.ksp.impl.symbol.kotlin.KSFileImpl$filePath$2.invoke(KSFileImpl.kt:58)
	at com.google.devtools.ksp.impl.symbol.kotlin.KSFileImpl$filePath$2.invoke(KSFileImpl.kt:57)
	at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
	at com.google.devtools.ksp.impl.symbol.kotlin.KSFileImpl.getFilePath(KSFileImpl.kt:57)
	at ksp.com.google.devtools.ksp.common.IncrementalContextBase.getRelativeFile(IncrementalContextBase.kt:108)
	at ksp.com.google.devtools.ksp.common.IncrementalContextBase.access$getRelativeFile(IncrementalContextBase.kt:62)
	at ksp.com.google.devtools.ksp.common.IncrementalContextBase$updateCachesAndOutputs$1.invoke(IncrementalContextBase.kt:436)
	at ksp.com.google.devtools.ksp.common.IncrementalContextBase$updateCachesAndOutputs$1.invoke(IncrementalContextBase.kt:429)
	at ksp.com.google.devtools.ksp.common.IncrementalContextBase.closeFilesOnException(IncrementalContextBase.kt:409)
	at ksp.com.google.devtools.ksp.common.IncrementalContextBase.updateCachesAndOutputs(IncrementalContextBase.kt:429)
	at com.google.devtools.ksp.impl.KotlinSymbolProcessing.execute(KotlinSymbolProcessing.kt:591)
	at com.google.devtools.ksp.impl.KSPLoader$Companion.loadAndRunKSP(KSPLoader.kt:37)
	at com.google.devtools.ksp.impl.KSPLoader.loadAndRunKSP(KSPLoader.kt)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at com.google.devtools.ksp.gradle.KspAAWorkerAction.execute(KspAATask.kt:525)
	at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:63)
	at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:66)
	at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:62)
	at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:100)
	at org.gradle.workers.internal.NoIsolationWorkerFactory$1.lambda$execute$0(NoIsolationWorkerFactory.java:62)
	at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:44)
	at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:41)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:209)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
	at org.gradle.workers.internal.AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41)
	at org.gradle.workers.internal.NoIsolationWorkerFactory$1.execute(NoIsolationWorkerFactory.java:59)
	at org.gradle.workers.internal.DefaultWorkerExecutor.lambda$submitWork$0(DefaultWorkerExecutor.java:174)
	at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:194)
	at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.access$700(DefaultConditionalExecutionQueue.java:127)
	at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner$1.run(DefaultConditionalExecutionQueue.java:169)
	at org.gradle.internal.Factories$1.create(Factories.java:31)
	at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:263)
	at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:127)
	at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:132)
	at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:164)
	at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:133)
	... 2 more

@technoir42
Copy link
Contributor

I can reliably reproduce the error when building an Android standalone test module when both test and application modules use Room or Glide KSP processor.

@ZacSweers
Copy link
Contributor

Also seeing this reproduce 100% of the time in our project since updating to 1.0.26 and testing KSP2

@ZacSweers
Copy link
Contributor

More importantly, I am also seeing this coming from KSP itself. No custom processors are in the stacktrace

Caused by: ksp.org.jetbrains.kotlin.analysis.api.lifetime.KaInvalidLifetimeOwnerAccessException: Access to invalid ksp.org.jetbrains.kotlin.analysis.api.platform.lifetime.KotlinAlwaysAccessibleLifetimeToken@258dd7ef: PSI has changed since creation	
	at ksp.org.jetbrains.kotlin.analysis.api.fir.symbols.KaFirFileSymbol.getPsi(KaFirFileSymbol.kt:58)	
	at com.google.devtools.ksp.impl.symbol.kotlin.KSFileImpl.getPsi(KSFileImpl.kt:44)	
	at com.google.devtools.ksp.impl.symbol.kotlin.KSFileImpl.access$getPsi(KSFileImpl.kt:38)	
	at com.google.devtools.ksp.impl.symbol.kotlin.KSFileImpl$filePath$2.invoke(KSFileImpl.kt:58)	
	at com.google.devtools.ksp.impl.symbol.kotlin.KSFileImpl$filePath$2.invoke(KSFileImpl.kt:57)	
	at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)	
	at com.google.devtools.ksp.impl.symbol.kotlin.KSFileImpl.getFilePath(KSFileImpl.kt:57)	
	at ksp.com.google.devtools.ksp.common.IncrementalContextBase.getRelativeFile(IncrementalContextBase.kt:108)	
	at ksp.com.google.devtools.ksp.common.IncrementalContextBase.access$getRelativeFile(IncrementalContextBase.kt:62)	
	at ksp.com.google.devtools.ksp.common.IncrementalContextBase$updateCachesAndOutputs$1.invoke(IncrementalContextBase.kt:436)	
	at ksp.com.google.devtools.ksp.common.IncrementalContextBase$updateCachesAndOutputs$1.invoke(IncrementalContextBase.kt:429)	
	at ksp.com.google.devtools.ksp.common.IncrementalContextBase.closeFilesOnException(IncrementalContextBase.kt:409)	
	at ksp.com.google.devtools.ksp.common.IncrementalContextBase.updateCachesAndOutputs(IncrementalContextBase.kt:429)	
	at com.google.devtools.ksp.impl.KotlinSymbolProcessing.execute(KotlinSymbolProcessing.kt:591)	
	at com.google.devtools.ksp.impl.KSPLoader$Companion.loadAndRunKSP(KSPLoader.kt:37)	
	at com.google.devtools.ksp.impl.KSPLoader.loadAndRunKSP(KSPLoader.kt)

@ZacSweers
Copy link
Contributor

This is also a project that worked with KSP2 in 1.0.25

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
8 participants