Buggy code:
@ SuppressCodecs ( { "Direct" , "Memory" } ) public class TestBagOfPostings extends LuceneTestCase { public void test ( ) throws Exception { List < String > postingsList = new ArrayList < > ( ) ; int numTerms = atLeast ( 300 ) ; final int maxTermsPerDoc = TestUtil . nextInt ( random ( ) , 10 , 20 ) ; boolean isSimpleText = "SimpleText" . equals ( TestUtil . getPostingsFormat ( "field" ) ) ; IndexWriterConfig iwc = newIndexWriterConfig ( random ( ) , TEST_VERSION_CURRENT , new org . apache . lucene . analysis . MockAnalyzer ( random ( ) ) ) ; if ( ( isSimpleText || ( ( iwc . getMergePolicy ( ) ) instanceof MockRandomMergePolicy ) ) && ( ( TEST_NIGHTLY ) || ( ( RANDOM_MULTIPLIER ) > 1 ) ) ) { numTerms //= 2 ; } if ( VERBOSE ) { System . out . println ( ( "maxTermsPerDoc=" + maxTermsPerDoc ) ) ; System . out . println ( ( "numTerms=" + numTerms ) ) ; } for ( int i = 0 ; i < numTerms ; i ++ ) { String term = Integer . toString ( i ) ; for ( int j = 0 ; j < i ; j ++ ) { postingsList . add ( term ) ; } } Collections . shuffle ( postingsList , random ( ) ) ; final ConcurrentLinkedQueue < String > postings = new ConcurrentLinkedQueue < > ( postingsList ) ; Directory dir = newFSDirectory ( createTempDir ( "bagofpostings" ) ) ; final RandomIndexWriter iw = new RandomIndexWriter ( random ( ) , dir , iwc ) ; int threadCount = TestUtil . nextInt ( random ( ) , 1 , 5 ) ; if ( VERBOSE ) { System . out . println ( ( "config:<seq2seq4repair_space>" + ( iw . w . getConfig ( ) ) ) ) ; System . out . println ( ( "threadCount=" + threadCount ) ) ; } Thread [ ] threads = new Thread [ threadCount ] ; final CountDownLatch startingGun = new CountDownLatch ( 1 ) ; for ( int threadID = 0 ; threadID < threadCount ; threadID ++ ) { threads [ threadID ] = new Thread ( ) { @ Override public void run ( ) { try { Document document = new Document ( ) ; Field field = newTextField ( "field" , "" , NO ) ; document . add ( field ) ; startingGun . await ( ) ; while ( ! ( postings . isEmpty ( ) ) ) { StringBuilder text = new StringBuilder ( ) ; Set < String > visited = new HashSet < > ( ) ; for ( int i = 0 ; i < maxTermsPerDoc ; i ++ ) { String token = postings . poll ( ) ; if ( token == null ) { break ; } if ( visited . contains ( token ) ) { postings . add ( token ) ; break ; } text . append ( '<seq2seq4repair_space>' ) ; text . append ( token ) ; visited . add ( token ) ; } field . setStringValue ( text . toString ( ) ) ; iw . addDocument ( document ) ; } } catch ( Exception e ) { throw new RuntimeException ( e ) ; } } } ; threads [ threadID ] . start ( ) ; } startingGun . countDown ( ) ; for ( Thread t : threads ) { t . join ( ) ; } iw . forceMerge ( 1 ) ; DirectoryReader ir = iw . getReader ( ) ; assertEquals ( 1 , ir . leaves ( ) . size ( ) ) ; AtomicReader air = ir . leaves ( ) . get ( 0 ) . reader ( ) ; Terms terms = air . terms ( "field" ) ; assertEquals ( ( numTerms - 1 ) , terms . size ( ) ) ; TermsEnum termsEnum = terms . iterator ( null ) ; BytesRef term ; while ( ( term = termsEnum . next ( ) ) != null ) { int value = Integer . parseInt ( term . utf8ToString ( ) ) ; assertEquals ( value , termsEnum . docFreq ( ) ) ; } ir . close ( ) ; <START_BUG> iw . close ( ) ; <END_BUG> dir . close ( ) ; } }

Fix:
iw . shutdown ( ) ;