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 variable of local class type used outside of the fragment

What it means

PrepareFailedException thrown by ExtractMethodProcessor when a local class is extracted along with the fragment, and a variable declared inside the fragment (and not the output variable) has that local class as its type. Such a variable cannot survive extraction: the new method would have to return it, but the local class type would then leak to callers that cannot name it, so the prepare step rejects the extraction, pointing at the offending variable.

Source

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

          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;
      }
    }
    return isExtracted;
  }

View on GitHub (pinned to be881553f2)

Solutions

  1. Promote the local class to a private nested or top-level class first; then the variable's type is nameable and extraction can proceed.
  2. Keep the variable inside the extracted fragment by restructuring so it is not used after the fragment (or return an interface/supertype instead).
  3. Include the later usages in the selection so the variable does not cross the boundary.
  4. Replace the local class with an existing interface type for the variable declaration where feasible.

Example fix

// before:
void m() {
  // selection:
  class L { int v; }
  L state = new L();
  // ... 'state' used after fragment -> fails
}

// after:
class Owner {
  private static class L { int v; }
  void m() {
    L state = new L();  // extraction of the body now possible
  }
}
Defensive patterns

Strategy: validation

Validate before calling

for (PsiVariable var : controlFlowWrapper.getUsedVariables()) {
  if (isDeclaredInside(var) && !var.equals(outputVariable)
      && PsiUtil.resolveClassInType(var.getType()) == extractedLocalClass) {
    // variable of local class type crosses the boundary: hoist the class or restructure
  }
}

Try / catch

try { processor.prepare(); } catch (PrepareFailedException e) { /* failing variable is attached; promote the local class to nested first */ }

Prevention

When it happens

Trigger: Extracting a fragment that declares 'class L {}' plus 'L var = new L();' where 'var' is used after the fragment (it appears in getUsedVariables), i.e. it would need to become an output of the extracted method with an unnameable type.

Common situations: Extracting builder/state-holder blocks built around a local class; selections that declare a local class and assign instances to variables consumed later in the method; refactoring helper classes introduced during stepwise extraction.

Related errors


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