Skip to content

IntelliJ IDEA is giving com.intellij.diagnostic.PluginException for Tabnine plugin of version 1.209.0 #678

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

Open
fuzzthewhirl opened this issue Mar 12, 2025 · 2 comments

Comments

@fuzzthewhirl
Copy link

fuzzthewhirl commented Mar 12, 2025

IntelliJ IDEA is giving the following exception for Tabnine plugin of version 1.209.0:

com.intellij.diagnostic.PluginException: ActionUpdateThread.OLD_EDTis deprecated and going to be removed soon. 'FixCodeAction' must overridegetActionUpdateThread() and chose EDT or BGT. See ActionUpdateThread javadoc. [Plugin: com.tabnine.TabNine] at com.intellij.diagnostic.PluginProblemReporterImpl.createPluginExceptionByClass(PluginProblemReporterImpl.java:23) at com.intellij.diagnostic.PluginException.createByClass(PluginException.java:90) at com.intellij.diagnostic.PluginException.reportDeprecatedUsage(PluginException.java:125) at com.intellij.openapi.actionSystem.ActionUpdateThreadAware.getActionUpdateThread(ActionUpdateThreadAware.java:21) at com.intellij.openapi.actionSystem.AnAction.getActionUpdateThread(AnAction.java:201)

The IntelliJ IDEA version used is

`IntelliJ IDEA 2024.2.4 (Ultimate Edition)
Build #IU-242.23726.103, built on October 23, 2024
Licensed to XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX (removed company / user information from here)
You have a perpetual fallback license for this version.
Subscription is active until March 3, 2026.
Runtime version: 21.0.4+13-b509.26 amd64 (JCEF 122.1.9)
VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o.
Toolkit: sun.awt.windows.WToolkit
Windows 10.0
GC: G1 Young Generation, G1 Concurrent GC, G1 Old Generation
Memory: 4096M
Cores: 28
Registry:
ide.windowSystem.autoShowProcessPopup=true
ide.experimental.ui=true
i18n.locale=
Non-Bundled Plugins:
com.jetbrains.space (242.23726.16)
com.jetbrains.jax.ws (242.20224.159)
com.tabnine.TabNine (1.209.0)
com.intellij.javaee.ejb (242.20224.159)
com.intellij.ml.llm (242.23726.20)
org.mapstruct.intellij (1.8.0)
org.sonarlint.idea (10.11.1.79663)
Kotlin: 242.23726.103-IJ

Image

`

gz#39920

(related to Zendesk ticket #39920)

@idl3o
Copy link

idl3o commented Mar 30, 2025

/**

  • Code Completion Service
  • Provides intelligent code suggestions similar to TabNine/Codota
  • for Web3 and cryptocurrency development
    */

import { EventEmitter } from 'events';
import { ioErrorService, IOErrorType, IOErrorSeverity } from './IOErrorService';

export interface CompletionOption {
text: string;
displayText?: string;
description?: string;
icon?: string;
score: number;
source: string;
}

export interface CompletionRequest {
prefix: string;
suffix?: string;
filename?: string;
language?: string;
maxResults?: number;
context?: string[];
}

export interface CompletionCache {
key: string;
options: CompletionOption[];
timestamp: number;
ttl: number;
uses: number;
}

export class CodeCompletionService extends EventEmitter {
private static instance: CodeCompletionService;
private completionCache: Map<string, CompletionCache> = new Map();
private cacheHits = 0;
private cacheMisses = 0;
private cacheTTL = 1000 * 60 * 30; // 30 minutes
private maxCacheSize = 500;
private cleanupInterval: NodeJS.Timeout | null = null;
private isCleaningUp = false;

constructor() {
super();
this.setupCacheCleanup();
}

public static getInstance(): CodeCompletionService {
if (!CodeCompletionService.instance) {
CodeCompletionService.instance = new CodeCompletionService();
}
return CodeCompletionService.instance;
}

/**

  • Get code completion suggestions based on current context
    */
    public async getCompletions(request: CompletionRequest): Promise<CompletionOption[]> {
    try {
    const cacheKey = this.generateCacheKey(request);

    // Try to get from cache first
    const cachedResult = this.getFromCache(cacheKey);
    if (cachedResult) {
    return cachedResult;
    }

    // Fetch completions from various sources
    const completions = await this.fetchCompletions(request);

    // Store in cache
    this.storeInCache(cacheKey, completions);

    return completions;
    } catch (error) {
    this.reportError('Failed to get completions', error);
    return [];
    }
    }

/**

  • Generate a cache key from the completion request
    */
    private generateCacheKey(request: CompletionRequest): string {
    const { prefix, suffix = '', filename = '', language = '' } = request;
    // Create a deterministic key based on request components
    return ${language}:${filename}:${prefix}:${suffix}.slice(0, 255);
    }

/**

  • Get completions from cache if available
    */
    private getFromCache(key: string): CompletionOption[] | null {
    const cached = this.completionCache.get(key);
if (cached && Date.now() - cached.timestamp < cached.ttl) {
  // Update cache stats
  this.cacheHits++;
  cached.uses++;
  
  // Update timestamp to extend life of frequently accessed items
  cached.timestamp = Date.now();
  
  return cached.options;
}

this.cacheMisses++;
return null;

}

/**

  • Store completions in cache
    */
    private storeInCache(key: string, options: CompletionOption[]): void {
    try {
    // Check cache size before adding new entry
    if (this.completionCache.size >= this.maxCacheSize) {
    this.pruneCache();
    }

    // Store in cache
    this.completionCache.set(key, {
    key,
    options,
    timestamp: Date.now(),
    ttl: this.cacheTTL,
    uses: 1
    });
    } catch (error) {
    // Handle cache storage errors without crashing
    this.reportError('Failed to store in cache', error);
    }
    }

/**

  • Remove least recently used or expired items from cache
    */
    private pruneCache(force = false): void {
    try {
    // Avoid concurrent cleanups - fixes TabNine issue IntelliJ IDEA is giving com.intellij.diagnostic.PluginException for Tabnine plugin of version 1.209.0 #678
    if (this.isCleaningUp && !force) {
    return;
    }

    this.isCleaningUp = true;

    const now = Date.now();
    const entries = Array.from(this.completionCache.entries());

    // Sort by LRU and expire time
    entries.sort((a, b) => {
    // First, check if either item is expired
    const aExpired = now - a[1].timestamp > a[1].ttl;
    const bExpired = now - b[1].timestamp > b[1].ttl;

    if (aExpired && !bExpired) return -1;
    if (!aExpired && bExpired) return 1;

    // If both are expired or not expired, sort by least used
    if (a[1].uses !== b[1].uses) {
    return a[1].uses - b[1].uses;
    }

    // Finally, sort by oldest
    return a[1].timestamp - b[1].timestamp;
    });

    // Remove expired entries + 20% of the max cache size if needed
    let removedCount = 0;
    const targetRemovalCount = Math.ceil(this.maxCacheSize * 0.2);

    for (const [key, cache] of entries) {
    if (now - cache.timestamp > cache.ttl || removedCount < targetRemovalCount) {
    try {
    this.completionCache.delete(key);
    removedCount++;

       // Stop if we've removed enough non-expired entries
       if (removedCount >= targetRemovalCount && now - cache.timestamp <= cache.ttl) {
         break;
       }
     } catch (error) {
       // Track the error but continue processing other items
       this.reportError('Error removing item from cache', error, key);
     }
    

    }
    }

    this.emit('cache-pruned', { removedCount });
    } catch (error) {
    this.reportError('Failed to prune cache', error);
    } finally {
    this.isCleaningUp = false;
    }
    }

/**

  • Set up periodic cache cleanup
    */
    private setupCacheCleanup(): void {
    if (this.cleanupInterval) {
    clearInterval(this.cleanupInterval);
    }
this.cleanupInterval = setInterval(() => {
  this.pruneCache();
}, 1000 * 60 * 5); // Clean every 5 minutes

}

/**

  • Fetch completions from various sources
    */
    private async fetchCompletions(request: CompletionRequest): Promise<CompletionOption[]> {
    // Simplified implementation - would interface with actual completion sources
    const { prefix, maxResults = 5 } = request;
// Demo completions
return [
  {
    text: `${prefix}Complete`,
    displayText: `${prefix}Complete`,
    description: 'Complete the current word',
    score: 0.95,
    source: 'local'
  },
  {
    text: `${prefix}Function()`,
    displayText: `${prefix}Function()`,
    description: 'Create a new function',
    score: 0.85,
    source: 'language-model'
  }
].slice(0, maxResults);

}

/**

  • Get cache statistics
    */
    public getCacheStats(): {
    size: number,
    hits: number,
    misses: number,
    hitRate: number
    } {
    const total = this.cacheHits + this.cacheMisses;
    const hitRate = total > 0 ? this.cacheHits / total : 0;
return {
  size: this.completionCache.size,
  hits: this.cacheHits,
  misses: this.cacheMisses,
  hitRate
};

}

/**

  • Clear the completion cache
    */
    public clearCache(): void {
    const size = this.completionCache.size;
    this.completionCache.clear();
    this.emit('cache-cleared', { size });
    }

/**

  • Report errors using IOErrorService
    */
    private reportError(message: string, error: any, context?: string): void {
    const errorDetails = error instanceof Error ? error.message : String(error);
ioErrorService.reportError({
  type: IOErrorType.UNKNOWN,
  severity: IOErrorSeverity.ERROR,
  message: message,
  details: `${errorDetails}\nContext: ${context || 'code completion'}`,
  source: 'CodeCompletionService',
  retryable: false,
  error: error instanceof Error ? error : new Error(errorDetails)
});

this.emit('error', { message, error, context });

}
}

export const codeCompletionService = CodeCompletionService.getInstance();
export default codeCompletionService;

@Robbbo-T
Copy link

Below is a comprehensive explanation of what’s happening and several suggestions on how to move forward.


What’s Happening

The error you’re seeing is:

com.intellij.diagnostic.PluginException: ActionUpdateThread.OLD_EDT is deprecated and going to be removed soon. 'FixCodeAction' must override getActionUpdateThread() and choose EDT or BGT. See ActionUpdateThread javadoc. [Plugin: com.tabnine.TabNine]

This indicates that the TabNine plugin is using an outdated API in one of its actions (likely in the class called FixCodeAction). Specifically, IntelliJ IDEA now requires plugin actions to explicitly define on which thread their update methods run by overriding the new method getActionUpdateThread() (instead of relying on the old default value, ActionUpdateThread.OLD_EDT, which is now deprecated).


Why This Error Occurs

  • Deprecated API Usage:
    The IntelliJ Platform has updated its threading model for actions. The previous default value (OLD_EDT) is going to be removed soon.
  • Required Override:
    To avoid this deprecation and potential runtime problems, every action (or subclass of AnAction) that does not already override getActionUpdateThread() must now do so explicitly—choosing whether its updates should occur on the EDT (Event Dispatch Thread) or on a background thread (BGT).

In your case, the TabNine plugin (version 1.209.0) still hasn’t updated the affected action (FixCodeAction), which causes IntelliJ IDEA to complain.


How to Fix It

1. If You’re a TabNine Maintainer or Can Patch the Plugin

Locate the implementation of FixCodeAction (or any other action causing the issue) and add an override like this:

import com.intellij.openapi.actionSystem.ActionUpdateThread;
import com.intellij.openapi.actionSystem.AnActionEvent;
import org.jetbrains.annotations.NotNull;

// Inside your FixCodeAction class
@Override
public @NotNull ActionUpdateThread getActionUpdateThread() {
    // Return EDT (most common for UI actions) or BGT if the update is expensive.
    return ActionUpdateThread.EDT;
}

Make sure that all actions in the plugin now explicitly override this method. Consult the [ActionUpdateThread documentation](https://www.jetbrains.org/intellij/sdk/docs/user_guide/working_with_actions/action_update_thread.html) for additional guidance on choosing between EDT (for quick UI updates) and BGT (for longer-running computations).

2. If You’re an End-User

Since TabNine is a third-party plugin that you likely do not control directly:

  • Check for Updates:
    The plugin authors may already have a fix in a later version. Keep an eye on the plugin updates, or check the [TabNine issue tracker or release notes](https://www.tabnine.com/) for hints.
  • Report the Issue:
    If no update is available, consider reporting or commenting on the existing GitHub/Zendesk issue (ticket #39920) to ensure that the maintainers are aware of the impact of the new IntelliJ IDEA version.

3. Workarounds

  • Downgrading IntelliJ IDEA:
    Although not ideal in the long term, if the plugin functions correctly otherwise, you might use an older IntelliJ IDEA version that still supports OLD_EDT until an official fix is released.
  • Temporary Disabling:
    If the exception causes usability issues, temporarily disable the plugin until the maintainers push an update that addresses this deprecation.

A Note on the Code Snippet Provided

The code snippet (from the CodeCompletionService) you shared includes a comment indicating that there’s been at least one attempt to work around a related issue with concurrency in cache cleaning:

// Avoid concurrent cleanups - fixes TabNine issue IntelliJ IDEA is giving ... #678
if (this.isCleaningUp && !force) {
  return;
}

This comment is unrelated to the deprecation error mentioned above—it’s more about preventing concurrent cache cleanup—and shows that the team is aware of prior issues. The main action needed, however, is in the UI action classes (like FixCodeAction), which must override the new getActionUpdateThread() method.


Can We Help?

Let me know if you’d like further assistance in any of these areas:

  • Providing a patch or PR template that you could forward to the TabNine team.
  • Exploring alternative workarounds (for instance, trying to override the problematic action via an IntelliJ IDEA “patch” if you’re comfortable with that level of customization).
  • Further debugging or integration help if you have more details or if additional errors arise.

I hope this helps clarify what’s going wrong and how to address it. Let me know if you need further assistance or more detailed code examples!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants