After migrating from KSP1 to KSP2, we intermittent...
# ksp
e
After migrating from KSP1 to KSP2, we intermittently see the following crash from Dagger's shaded xprocessing during ksp execution on CI.
Copy code
java.lang.IllegalStateException: Class com.example.MyViewModel should have only one super class. Found 2
  (com.example.BaseViewModel<...>, com.example.MyViewModelApi).
      at dagger.spi.internal.shaded.androidx.room.compiler.processing.ksp.KspType.superTypes_delegate$lambda$10(KspType.kt:147)
It is incorrectly classifying an interface as a class for some reason, leading to this issue. I can't find any existing issues on Dagger or Ksp GitHub about this. Unfortunately, it happens very sporadically and I don't have a reproducer. Would it be helpful to create an issue for Dagger and/or KSP?
Full stacktrace:
Copy code
java.lang.IllegalStateException: Class com.example.MyViewModel should have only one super class. Found 2
  (com.example.BaseViewModel<...>, com.example.MyViewModelApi).
      at dagger.spi.internal.shaded.androidx.room.compiler.processing.ksp.KspType.superTypes_delegate$lambda$10(KspType.kt:147)
at dagger.spi.internal.shaded.androidx.room.compiler.processing.ksp.KspType.superTypes_delegate$lambda$10(KspType.kt:147)                                                
      at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:86)                                                                                                                   
      at dagger.spi.internal.shaded.androidx.room.compiler.processing.ksp.KspType.getSuperTypes(KspType.kt:105)                                                                
      at dagger.internal.codegen.xprocessing.XTypes.nonObjectSuperclass(XTypes.java:430)                                                                                       
      at dagger.internal.codegen.binding.InjectionSiteFactory.getInjectionSites(InjectionSiteFactory.java:67)                                                                  
      at dagger.internal.codegen.binding.BindingFactory.assistedInjectionBinding(BindingFactory.java:156)                                                                      
      at dagger.internal.codegen.validation.InjectBindingRegistryImpl.tryRegisterConstructor(InjectBindingRegistryImpl.java:277)                                               
      at dagger.internal.codegen.validation.InjectBindingRegistryImpl.lambda$getOrFindInjectionBinding$0(InjectBindingRegistryImpl.java:378)                                   
      at dagger.internal.codegen.validation.InjectBindingRegistryImpl.getOrFindInjectionBinding(InjectBindingRegistryImpl.java:376)                                            
      at dagger.internal.codegen.binding.LegacyBindingGraphFactory$Resolver.lookUpBindings(LegacyBindingGraphFactory.java:417)                                             
      at dagger.internal.codegen.binding.LegacyBindingGraphFactory$Resolver.resolve(LegacyBindingGraphFactory.java:734)                                                    
      at dagger.internal.codegen.binding.LegacyBindingGraphFactory$Resolver.resolveDependencies(LegacyBindingGraphFactory.java:749)                                        
      at dagger.internal.codegen.binding.LegacyBindingGraphFactory$Resolver.resolve(LegacyBindingGraphFactory.java:736)                                                    
      at dagger.internal.codegen.binding.LegacyBindingGraphFactory$Resolver.resolveDependencies(LegacyBindingGraphFactory.java:749)                                        
      at dagger.internal.codegen.binding.LegacyBindingGraphFactory$Resolver.resolve(LegacyBindingGraphFactory.java:736)                                                    
      at dagger.internal.codegen.binding.LegacyBindingGraphFactory$Resolver.resolveDependencies(LegacyBindingGraphFactory.java:749)                                        
      at dagger.internal.codegen.binding.LegacyBindingGraphFactory$Resolver.resolve(LegacyBindingGraphFactory.java:736)                                                    
      at dagger.internal.codegen.binding.LegacyBindingGraphFactory$Resolver.resolveDependencies(LegacyBindingGraphFactory.java:749)                                        
      at dagger.internal.codegen.binding.LegacyBindingGraphFactory$Resolver.resolve(LegacyBindingGraphFactory.java:736)                                                    
      at dagger.internal.codegen.binding.LegacyBindingGraphFactory$Resolver.resolveDependencies(LegacyBindingGraphFactory.java:749)                                        
      at dagger.internal.codegen.binding.LegacyBindingGraphFactory$Resolver.resolve(LegacyBindingGraphFactory.java:736)                                                    
      at dagger.internal.codegen.binding.LegacyBindingGraphFactory$Resolver.resolveDependencies(LegacyBindingGraphFactory.java:749)                                        
      at dagger.internal.codegen.binding.LegacyBindingGraphFactory$Resolver.resolve(LegacyBindingGraphFactory.java:736)                                                    
      at dagger.internal.codegen.binding.LegacyBindingGraphFactory.lambda$createLegacyBindingGraph$1(LegacyBindingGraphFactory.java:137)                                   
      at dagger.internal.codegen.binding.LegacyBindingGraphFactory.createLegacyBindingGraph(LegacyBindingGraphFactory.java:132)                                            
      at dagger.internal.codegen.binding.LegacyBindingGraphFactory.create(LegacyBindingGraphFactory.java:120)                                                              
      at dagger.internal.codegen.binding.BindingGraphFactory.create(BindingGraphFactory.java:111)                                                                          
      at dagger.internal.codegen.processingstep.ComponentProcessingStep.processRootComponent(ComponentProcessingStep.java:112)                                             
      at dagger.internal.codegen.processingstep.ComponentProcessingStep.process(ComponentProcessingStep.java:83)                                                           
      at dagger.internal.codegen.processingstep.ComponentProcessingStep.process(ComponentProcessingStep.java:48)                                                           
      at dagger.internal.codegen.processingstep.TypeCheckingProcessingStep.lambda$process$0(TypeCheckingProcessingStep.java:96)                                            
      at com.google.common.collect.RegularImmutableMap.forEach(RegularImmutableMap.java:293)                                                                               
      at dagger.internal.codegen.processingstep.TypeCheckingProcessingStep.process(TypeCheckingProcessingStep.java:74)                                                     
      at dagger.internal.codegen.processingstep.TypeCheckingProcessingStep.process(TypeCheckingProcessingStep.java:49)                                                     
      at dagger.spi.internal.shaded.androidx.room.compiler.processing.XProcessingStep.process(XProcessingStep.kt:57)                                                       
      at dagger.spi.internal.shaded.androidx.room.compiler.processing.CommonProcessorDelegate.processRound(XBasicAnnotationProcessor.kt:134)                               
      at dagger.spi.internal.shaded.androidx.room.compiler.processing.ksp.KspBasicAnnotationProcessor.process(KspBasicAnnotationProcessor.kt:62)                           
      at com.google.devtools.ksp.impl.KotlinSymbolProcessing$execute$1$1.invoke(KotlinSymbolProcessing.kt:566)                                                             
      at com.google.devtools.ksp.impl.KotlinSymbolProcessing$execute$1$1.invoke(KotlinSymbolProcessing.kt:564)                                                             
      at ksp.com.google.devtools.ksp.common.IncrementalContextBase.closeFilesOnException(IncrementalContextBase.kt:403)                                                    
      at com.google.devtools.ksp.impl.KotlinSymbolProcessing.execute(KotlinSymbolProcessing.kt:564)                                                                        
      at com.google.devtools.ksp.impl.KSPLoader$Companion.loadAndRunKSP(KSPLoader.kt:37)
The class in question:
Copy code
// Module A
  class MyViewModel constructor(...)
      : BaseViewModel<...>(...),   // CLASS from module B
        MyViewModelApi {           // INTERFACE from module C
The xprocessing superTypes property partitions super types using classKind == ClassKind.CLASS. The interface from module C is intermittently classified as ClassKind.CLASS instead of ClassKind.INTERFACE, causing the "should have only one super class" error. I asked claude code to try to analyze it, and it came up with this theory
Copy code
KSP2's Analysis API occasionally returns incorrect KaClassKind.CLASS for KaClassSymbol resolved from compiled binary dependencies when the Analysis API's internal cache (VFS
   cache, FIR resolution state) is stale
b
Yeah, this sounds like a lower level than Dagger/XProcessing, so I think filing a KSP bug makes sense. There's not much Dagger/XProcessing can do if KSP is telling us you have two super classes. Fwiw, it sounds similar to an issue I filed a while ago where KSP assumes CLASS if a symbol cannot be resolved (e.g. if the interface will be generated in a future round): https://github.com/google/ksp/issues/1443. That case was less straightforward what to do. In your case, I think it's clearly a bug.
e
Thanks for the input, I'll file an issue.