stanfordnlp/CoreNLP · error · IllegalStateException

Cannot nest Redwood threaded environments

Error message

Cannot nest Redwood threaded environments

What it means

Redwood.startThreads(title) throws IllegalStateException if Redwood is already inside a threaded environment (isThreaded == true). Threaded environments used for concurrent logging cannot be nested; you must call endThreads() before starting another one.

Solutions

  1. Call Redwood.endThreads() after the threaded section before any other startThreads()
  2. Guard the call: only startThreads if !Redwood.isThreaded (or restructure so only the top level starts it)
  3. Wrap the threaded section in try/finally so endThreads always runs
  4. Move startThreads to the outermost caller (e.g. main) and remove inner ones

Example fix

// before
Redwood.startThreads("workers");
doWork();
Redwood.startThreads("more"); // throws
// after
Redwood.startThreads("workers");
try { doWork(); } finally { Redwood.endThreads(); }
Redwood.startThreads("more");
try { moreWork(); } finally { Redwood.endThreads(); }
Defensive patterns

Strategy: validation

Validate before calling

if (!Redwood.isThreaded) {
  Redwood.startThreads(title);
}

Try / catch

try {
  Redwood.startThreads(title);
} catch (IllegalStateException e) {
  // already threaded — reuse the existing threaded environment
}

Prevention

When it happens

Trigger: Calling Redwood.startThreads(...) twice without an intervening Redwood.endThreads(); calling startThreads from re-entrant/nested code (e.g. main starts threads and calls a method that also starts them).

Common situations: Two library subsystems each wrapping their work in Redwood threaded environments; recursive algorithms that call startThreads per level; forgotten endThreads on an early-return path.

Related errors


AI-assisted analysis of stanfordnlp/CoreNLP@1b7edd19c4 (2026-09-10). Data as JSON: /api/errors/9f739bc286b673d1. Report an issue: GitHub.

Appendix: source

Thrown at src/edu/stanford/nlp/util/logging/Redwood.java:429

  /**
   * A utility method for closing calls to the anonymous startTrack() call.
   */
  public static void endTrack(){ endTrack(""); }


  /**
   * Start a multithreaded logging environment. Log messages will be real time
   * from one of the threads; as each thread finishes, another thread begins logging,
   * first by making up the backlog, and then by printing any new log messages.
   * A thread signals that it has finished logging with the finishThread() function;
   * the multithreaded environment is ended with the endThreads() function.
   *
   * @param title The name of the thread group being started
   */
  public static void startThreads(String title){
    if(isThreaded){
      throw new IllegalStateException("Cannot nest Redwood threaded environments");
    }
    startTrack(FORCE,"Threads( "+title+" )");
    isThreaded = true;
  }

  /**
   * Signal that this thread will not log any more messages in the multithreaded
   * environment
   */
  public static void finishThread(){
    //--Create Task
    final long threadId = Thread.currentThread().getId();
    Runnable finish = () -> releaseThreadControl(threadId);
    //--Run Task
    if(isThreaded){
      //(case: multithreaded)
      attemptThreadControl( threadId, finish );
    } else {

View on GitHub (pinned to 1b7edd19c4)