{"record":{"id":"79e574fbf4fb93ff","repo":"JetBrains/intellij-community","slug":"thread-has-been-collected","errorCode":null,"errorMessage":"Thread has been collected","messagePattern":"Thread has been collected","errorType":"exception","errorClass":"EvaluateException","httpStatus":null,"severity":"error","filePath":"java/debugger/impl/src/com/intellij/debugger/jdi/StackFrameProxyImpl.java","lineNumber":193,"sourceCode":"      return getFrameIndexAsync().thenCompose(index -> {\n          // batch get frames from 1 to FRAMES_BATCH_MAX\n          // making this number very high does not help much because renderers invocation usually flush all caches\n          if (index > 0 && index < FRAMES_BATCH_MAX) {\n            try {\n              return DebuggerUtilsAsync.frames(threadRef, 0, Math.min(myThreadProxy.frameCount(), FRAMES_BATCH_MAX))\n                .thenApply(frames -> myStackFrame = frames.get(index));\n            }\n            catch (EvaluateException e) {\n              return CompletableFuture.failedFuture(e);\n            }\n          }\n          else {\n            return DebuggerUtilsAsync.frame(threadRef, index).thenApply(f -> myStackFrame = f);\n          }\n        })\n        .exceptionally(throwable -> {\n          if (DebuggerUtilsAsync.unwrap(throwable) instanceof ObjectCollectedException) {\n            throw new CompletionException(EvaluateExceptionUtil.createEvaluateException(JavaDebuggerBundle.message(\"evaluation.error.thread.collected\")));\n          }\n          throw (RuntimeException)throwable;\n        });\n    }\n\n    return CompletableFuture.completedFuture(myStackFrame);\n  }\n\n  @Override\n  public int getFrameIndex() throws EvaluateException {\n    DebuggerManagerThreadImpl.assertIsManagerThread();\n    checkValid();\n    if (myFrameIndex == -1) {\n      int count = myThreadProxy.frameCount();\n\n      if (myFrameFromBottomIndex > count) {\n        throw EvaluateExceptionUtil.createEvaluateException(new IncompatibleThreadStateException());\n      }","sourceCodeStart":175,"sourceCodeEnd":211,"githubUrl":"https://github.com/JetBrains/intellij-community/blob/be881553f2a76ac8b4ea53950d93f0de78295c19/java/debugger/impl/src/com/intellij/debugger/jdi/StackFrameProxyImpl.java#L175-L211","documentation":"Reported by StackFrameProxyImpl when asynchronously fetching a stack frame by index fails because the thread object was garbage-collected in the debuggee VM: JDI raises ObjectCollectedException, which is unwrapped from the future and translated into the localized evaluation.error.thread.collected message ('Thread has been collected'). The frame data is no longer reachable, so any inspection of it fails.","triggerScenarios":"DebuggerUtilsAsync.frame(threadRef, index) (or a cached frames refresh) completes exceptionally; DebuggerUtilsAsync.unwrap(throwable) is an ObjectCollectedException — the ThreadReference was collected by the debuggee GC (references not kept / collection enabled on the mirror), and the exceptionally block rethrows EvaluateExceptionUtil.createEvaluateException(evaluation.error.thread.collected).","commonSituations":"Stepping or evaluating on a thread that finished and became garbage before the request was processed; debugger holding weak references after the thread terminated; heavy GC in the debuggee while the UI requests frames; long-paused session where mirrors were collected.","solutions":["Refresh the debugger session (resume and re-suspend) to obtain fresh thread/frame mirrors","Restart the debug session if the thread has terminated — its frames cannot be recovered","Keep the debuggee under less GC pressure / avoid full GC while paused (increase heap)","Update the IDE: reference-retention of thread mirrors has seen fixes"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// before using a thread mirror across suspensions\nif (!threadRef.isCollected()) {\n  frames = DebuggerUtilsAsync.frame(threadRef, index).join();\n} else {\n  // drop the cached proxy; refresh thread list\n}","typeGuard":null,"tryCatchPattern":"frameFuture.exceptionally(t -> {\n  if (DebuggerUtilsAsync.unwrap(t) instanceof ObjectCollectedException) {\n    // re-fetch thread reference from vm.allThreads() and retry once\n  }\n  throw (RuntimeException) t;\n});","preventionTips":["Re-acquire thread references after resume/re-suspend instead of caching them","Avoid long pauses that let debuggee GC collect thread mirrors","Handle thread termination: treat collected-thread errors as session-refresh triggers"],"tags":["debugger","jdi","gc","thread","stack-frame"],"backgroundTag":null,"analyzedSha":"be881553f2a76ac8b4ea53950d93f0de78295c19","analyzedAt":"2026-08-14T14:13:06.425Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}