PSI element for DataKey("selectedItems") is provided on EDT by com.intellij.ui.popup.list.ListPopupImpl$MyList. Use `DataSink.lazy` to provide such data

Hi,

I have plugin code that adds a line marker. Works nice as long as I use the mouse to navigate. When I use the related items shortcut it opens a (different) popup and throws the exception for each of my items and brings up the “IDE error occurred” notification.

my code goes like this:

package io.openapiprocessor.intellij

import com.intellij.codeInsight.daemon.RelatedItemLineMarkerInfo
import com.intellij.codeInsight.daemon.RelatedItemLineMarkerProvider
import com.intellij.codeInsight.navigation.NavigationGutterIconBuilder
import com.intellij.icons.AllIcons
import com.intellij.openapi.components.service
import com.intellij.psi.PsiElement
import com.intellij.util.IconUtil
import org.jetbrains.yaml.psi.YAMLKeyValue
import org.slf4j.Logger
import org.slf4j.LoggerFactory

class OpenApiPathLineMarker: RelatedItemLineMarkerProvider()  {
    private val log: Logger = LoggerFactory.getLogger(this.javaClass.name)

    override fun collectNavigationMarkers(
        element: PsiElement,
        result: MutableCollection<in RelatedItemLineMarkerInfo<*>>
    ) {

        if (element !is YAMLKeyValue)
            return

        if(element.keyText != "paths")
            return

        if(!isOpenApi(element))
            return

        val pathTargetService = service<PathTargetService>()

        element.value?.children?.forEach { path ->
            if (path !is YAMLKeyValue)
                return@forEach

            val isPath = path.keyText.startsWith("/")
            if (!isPath) {
                log.warn("expected to find path but found {}", path.keyText)
            }

            // returns List<PsiElement> 
            val targets = pathTargetService.findPathTargets(path.project, path.keyText)

            if (targets.isEmpty()) {
                log.warn("found no targets!")
                return@forEach
            }

            val builder = NavigationGutterIconBuilder
                .create(icon)
                .setTooltipText(I18n.TOOLTIP_TEXT)
                .setPopupTitle(I18n.POPUP_TITLE)
                .setTargets(targets)

            result.add(builder.createLineMarkerInfo(path.key!!))
        }
    }

    private fun isOpenApi(element: YAMLKeyValue): Boolean {
        return element.parent.children.any {
            it.firstChild.text == "openapi"
        }
    }

    private val icon = IconUtil.scale(AllIcons.Nodes.Interface, null, 0.875f)

    object I18n {
        val TOOLTIP_TEXT = i18n("line.marker.openapi.path.tooltip")
        val POPUP_TITLE = i18n("line.marker.openapi.path.title")
    }
}

After several iterations with the ai (it usually provides code that does not compile, apologizes and then provides broken code again.. :wink:) it came up with this code:

            val lazyTargets: NotNullLazyValue<Collection<PsiElement>> = NotNullLazyValue.createValue {
                ApplicationManager.getApplication().runReadAction<Collection<PsiElement>> {
                    pathTargetService.findPathTargets(path.project, path.keyText)
                }
            }

But it doesn’t help, it still throws the exception. Using 2025.1 platform.

What would be the proper solution to avoid the exceptions?

com.intellij.diagnostic.PluginException: PSI element for DataKey("selectedItems") is provided on EDT by com.intellij.ui.popup.list.ListPopupImpl$MyList. Use `DataSink.lazy` to provide such data
	at com.intellij.diagnostic.PluginProblemReporterImpl.createPluginExceptionByClass(PluginProblemReporterImpl.java:23)
	at com.intellij.diagnostic.PluginException.createByClass(PluginException.java:90)
	at com.intellij.ide.impl.DataValidators.reportPsiElementOnEdt(DataValidators.java:126)
	at com.intellij.ide.impl.DataValidators.isDataValid(DataValidators.java:85)
	at com.intellij.ide.impl.DataValidators.validOrNull(DataValidators.java:78)
	at com.intellij.openapi.actionSystem.impl.MySink.set(PreCachedDataContext.kt:488)
	at com.intellij.ui.popup.util.PopupImplUtil.uiSnapshotForList(PopupImplUtil.java:67)
	at com.intellij.ui.popup.list.ListPopupImpl$MyList.uiDataSnapshot(ListPopupImpl.java:864)
	at com.intellij.openapi.actionSystem.impl.MySink.uiDataSnapshot(PreCachedDataContext.kt:530)
	at com.intellij.openapi.actionSystem.DataSink$Companion.uiDataSnapshot(UiDataProvider.kt:210)
	at com.intellij.openapi.actionSystem.impl.PreCachedDataContextKt.cacheProviderData(PreCachedDataContext.kt:411)
	at com.intellij.openapi.actionSystem.impl.PreCachedDataContextKt.cacheComponentsData(PreCachedDataContext.kt:394)
	at com.intellij.openapi.actionSystem.impl.PreCachedDataContextKt.access$cacheComponentsData(PreCachedDataContext.kt:1)
	at com.intellij.openapi.actionSystem.impl.PreCachedDataContext.<init>(PreCachedDataContext.kt:96)
	at com.intellij.openapi.actionSystem.impl.Utils.createAsyncDataContext(Utils.kt:163)
	at com.intellij.openapi.fileEditor.impl.IdeUiServiceImpl.createUiDataContext(IdeUiServiceImpl.java:79)
	at com.intellij.ide.impl.DataManagerImpl.getDataContext(DataManagerImpl.java:283)
	at com.intellij.ide.impl.DataManagerImpl.getDataContext(DataManagerImpl.java:309)
	at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher.dispatchKeyEvent(IdeKeyEventDispatcher.kt:297)
	at com.intellij.ide.IdeEventQueue.dispatchKeyEvent(IdeEventQueue.kt:515)
	at com.intellij.ide.IdeEventQueue._dispatchEvent$lambda$17(IdeEventQueue.kt:474)
	at com.intellij.openapi.application.impl.AnyThreadWriteThreadingSupport.runWriteIntentReadAction$lambda$6(AnyThreadWriteThreadingSupport.kt:274)
	at com.intellij.openapi.application.impl.AnyThreadWriteThreadingSupport.runWithTemporaryThreadLocal(AnyThreadWriteThreadingSupport.kt:204)
	at com.intellij.openapi.application.impl.AnyThreadWriteThreadingSupport.runWriteIntentReadAction(AnyThreadWriteThreadingSupport.kt:274)
	at com.intellij.openapi.application.impl.AnyThreadWriteThreadingSupport.runPreventiveWriteIntentReadAction(AnyThreadWriteThreadingSupport.kt:218)
	at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.kt:474)
	at com.intellij.ide.IdeEventQueue.dispatchEvent$lambda$12$lambda$11$lambda$10$lambda$9(IdeEventQueue.kt:307)
	at com.intellij.openapi.progress.impl.CoreProgressManager.computePrioritized(CoreProgressManager.java:864)
	at com.intellij.ide.IdeEventQueue.dispatchEvent$lambda$12$lambda$11$lambda$10(IdeEventQueue.kt:306)
	at com.intellij.ide.IdeEventQueueKt.performActivity$lambda$3(IdeEventQueue.kt:958)
	at com.intellij.openapi.application.TransactionGuardImpl.performActivity(TransactionGuardImpl.java:117)
	at com.intellij.ide.IdeEventQueueKt.performActivity(IdeEventQueue.kt:958)
	at com.intellij.ide.IdeEventQueue.dispatchEvent$lambda$12(IdeEventQueue.kt:301)
	at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.kt:341)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:207)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:128)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:117)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:113)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:105)
	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:92)

the PsiElement returned by my service is a PsiMethod.

is there any additional info I can provide?

oh great :astonished_face:

the exception does not show up if I build my plugin and install it from disk into intellij. It only seems to show up if I “Run Plugin” from the plugin project where intellij starts intellij with the plugin.

How should I know that… :zany_face:

So this is something I can ignore?

Hi, this should help you with NavigationGutterIconBuilder:

.setTargetRenderer(() -> new PsiTargetPresentationRenderer<>())