JetBrains/intellij-community · error · IncorrectOperationException

Cannot rename light class

Error message

Cannot rename light class

What it means

LightPsiClassBase is the base for synthetic, in-memory 'light' classes that are not backed by source text (e.g. classes inferred from class files, cache delegates, or synthesized wrappers). Because a light class has no source element to edit, its setName permanently throws IncorrectOperationException("Cannot rename light class").

Source

Thrown at java/java-psi-impl/src/com/intellij/psi/impl/light/LightPsiClassBase.java:218

  @Override
  public boolean isInheritor(@NotNull PsiClass baseClass, boolean checkDeep) {
    return InheritanceImplUtil.isInheritor(this, baseClass, checkDeep);
  }

  @Override
  public boolean isInheritorDeep(@NotNull PsiClass baseClass, @Nullable PsiClass classToByPass) {
    return InheritanceImplUtil.isInheritorDeep(this, baseClass, classToByPass);
  }

  @Override
  public @NotNull Collection<HierarchicalMethodSignature> getVisibleSignatures() {
    return PsiSuperMethodImplUtil.getVisibleSignatures(this);
  }

  @Override
  public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException {
    throw new IncorrectOperationException("Cannot rename light class");
  }

  @Override
  public @Nullable PsiDocComment getDocComment() {
    return null;
  }

  @Override
  public boolean isDeprecated() {
    return false;
  }

  @Override
  public boolean hasTypeParameters() {
    return PsiImplUtil.hasTypeParameters(this);
  }

  @Override

View on GitHub (pinned to be881553f2)

Solutions

  1. Before renaming, resolve to the source element: check element instanceof PsiCompiledElement or navigate with JavaPsiFacade.findClass and prefer the source class; skip if only a compiled/light mirror exists.
  2. Guard with a check such as !(aClass instanceof LightPsiClassBase) (or !aClass.isPhysical() / instanceof PsiCompiledElement) before calling setName.
  3. In rename refactors, use JavaRenameUtil/name suggesters that already filter non-renamable elements, or mark the handler unavailable for light classes.
  4. If you own the light class, override setName to redirect the rename to the underlying source class.

Example fix

// before
classRef.resolve().setName(newName); // resolves to LightPsiClassBase -> throws

// after
PsiElement target = classRef.resolve();
if (target instanceof PsiCompiledElement || target instanceof LightPsiClassBase) return; // not renamable
target.setName(newName);
Defensive patterns

Strategy: type-guard

Validate before calling

if (aClass instanceof LightPsiClassBase) return; // synthetic, not renamable

Type guard

static boolean isRenamableClass(PsiClass c) {
  return !(c instanceof LightPsiClassBase) && !(c instanceof PsiCompiledElement) && c.getNameIdentifier() != null;
}

Try / catch

try { aClass.setName(n); } catch (IncorrectOperationException e) { /* skip light class, log at most */ }

Prevention

When it happens

Trigger: Invoking PsiClass.setName on any LightPsiClassBase subclass: light classes created from compiled code (ClsClassImpl-style wrappers), PsiTypeParameter-like synthetics, or custom LightClass implementations; typically reached from a rename refactoring or direct setName call.

Common situations: A rename refactoring resolves a reference to a class without source (from a library .class or .jar) and tries to rename it; a plugin iterates classes and calls setName without checking canNavigate/to the source; tests that pick up light mirrors of source classes.

Related errors


AI-assisted analysis of JetBrains/intellij-community@be881553f2 (2026-08-14). Data as JSON: /api/errors/8e902ac8aebccafe. Report an issue: GitHub.