JetBrains/intellij-community · error · PrepareFailedException

Cannot extract method because the selected code fragment def

Error message

Cannot extract method because the selected code fragment defines local classes used outside of the fragment

What it means

PrepareFailedException thrown by ExtractMethodProcessor when a local or anonymous class is declared inside the selected fragment but referenced from code that remains outside it (remainingReferences non-empty). After extraction the class would move into the new method, so the leftover code in the original method could no longer resolve those references; the refactoring aborts instead of producing broken code.

Source

Thrown at java/java-impl-refactorings/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java:683

      final List<PsiElement> remainingReferences = Collections.synchronizedList(new ArrayList<>());
      ReferencesSearch.search(localClass).forEach(psiReference -> {
        final PsiElement element = psiReference.getElement();
        final boolean elementExtracted = isExtractedElement(element);
        if (elementExtracted && !classExtracted) {
          extractedReferences.add(element);
          return false;
        }
        if (!elementExtracted && classExtracted) {
          remainingReferences.add(element);
          return false;
        }
        return true;
      });
      if (!extractedReferences.isEmpty()) {
        throw new PrepareFailedException(JavaRefactoringBundle.message("extract.method.error.local.class.defined.outside"), extractedReferences.get(0));
      }
      if (!remainingReferences.isEmpty()) {
        throw new PrepareFailedException(JavaRefactoringBundle.message("extract.method.error.local.class.used.outside"), remainingReferences.get(0));
      }
      if (classExtracted) {
        for (PsiVariable variable : myControlFlowWrapper.getUsedVariables()) {
          if (isDeclaredInside(variable) && !variable.equals(myOutputVariable) && PsiUtil.resolveClassInType(variable.getType()) == localClass) {
            throw new PrepareFailedException(JavaRefactoringBundle.message("extract.method.error.local.class.variable.used.outside"), variable);
          }
        }
      }
    }
  }

  private boolean isExtractedElement(final PsiElement element) {
    boolean isExtracted = false;
    for(PsiElement psiElement: myElements) {
      if (PsiTreeUtil.isAncestor(psiElement, element, false)) {
        isExtracted = true;
        break;
      }

View on GitHub (pinned to be881553f2)

Solutions

  1. Extend the selection to cover the remaining usages of the local class as well.
  2. Hoist the local class out of the method into a private nested class, then extract the fragment (references now resolve via the class, not the local scope).
  3. Split the work: first inline or restructure the outside usages (e.g. store the instance in a variable returned or widened), then extract.
  4. Choose a smaller fragment that neither declares nor uses the local class.

Example fix

// before:
void m() {
  // selection: class Local { void go() {} }
  // ... extraction fails because the line below stays outside
  new Local().go();
}

// after (hoist):
class Owner {
  private static class Local { void go() {} }
  void m() {
    // extracted fragment can now use Owner.Local
    new Local().go();
  }
}
Defensive patterns

Strategy: validation

Validate before calling

for (PsiClass local : classesDeclaredInsideSelection) {
  if (isReferencedFromOutside(local, elements)) {
    // widen selection, or hoist the local class to a nested class before extracting
  }
}

Try / catch

try { processor.prepare(); } catch (PrepareFailedException e) { /* first remaining reference is provided; use it to extend selection */ }

Prevention

When it happens

Trigger: Selecting a range that contains 'class Local {...}' or 'new Runnable(){...}' while later statements in the same method (outside the selection) still use that class or its instances.

Common situations: Extracting the setup half of a method whose second half uses the created listener/local type; extracting a block that declares a local class used in a finally or later branch; automated extract-method suggestions that stop mid-method.

Related errors


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