{"record":{"id":"a6bad673b4c640bb","repo":"MyCATApache/Mycat-Server","slug":"writer-already-closed-cannot-be-reopened","errorCode":null,"errorMessage":"Writer already closed. Cannot be reopened.","messagePattern":"Writer already closed\\. Cannot be reopened\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"src/main/java/io/mycat/memory/unsafe/storage/DiskRowWriter.java","lineNumber":105,"sourceCode":"          OutputStream compressStream ,\n          boolean syncWrites,\n          ConnectionId blockId) throws IOException {\n\n    this.file = file;\n    this.serializerInstance = serializerInstance;\n    this.bufferSize = bufferSize;\n    this.compressStream = compressStream;\n    this.syncWrites = syncWrites;\n    this.blockId = blockId;\n    initialPosition = file.length();\n    reportedPosition = initialPosition;\n  }\n\n\n  public DiskRowWriter open() throws FileNotFoundException {\n\n    if (hasBeenClosed) {\n      throw new IllegalStateException(\"Writer already closed. Cannot be reopened.\");\n    }\n\n    fos = new FileOutputStream(file,true);\n    ts = new TimeTrackingOutputStream(/**writeMetrics,*/ fos);\n    channel = fos.getChannel();\n    bs = new BufferedOutputStream(ts,bufferSize);\n    objOut = serializerInstance.serializeStream(bs);\n    initialized = true;\n\n    return this;\n\n  }\n\n\n  @Override\n  public void close() {\n    if (initialized) {\n      try {","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/MyCATApache/Mycat-Server/blob/65f8d8beb752f935752f2a0eec0ab017facab9ef/src/main/java/io/mycat/memory/unsafe/storage/DiskRowWriter.java#L87-L123","documentation":"DiskRowWriter.open() re-acquires the file output stream, channel, and buffered stream. Once the writer has been closed, hasBeenClosed is set and any further open() call throws IllegalStateException 'Writer already closed. Cannot be reopened.' Closed writers are intentionally not reusable.","triggerScenarios":"Calling write() (which internally calls open()) after close() was invoked on the same DiskRowWriter; reusing a writer object across lifecycle phases after finishing a batch.","commonSituations":"Retrying a failed append with the same writer after close; object pooling code that returns closed writers to a pool; a consumer callback firing after the writer finished a spill file.","solutions":["Create a new DiskRowWriter for the file instead of reopening the closed one","Track writer state in the caller and stop issuing writes after close","If retry semantics are needed, wrap write in a factory method that builds a fresh writer per attempt"],"exampleFix":"// before\nwriter.close();\nwriter.write(row); // IllegalStateException\n// after\nwriter.close();\nDiskRowWriter writer2 = new DiskRowWriter(file, bufferSize);\nwriter2.open().write(row);","handlingStrategy":"type-guard","validationCode":"if (!writer.isClosed()) { writer.write(row); } else { writer = writerFactory.create(file); writer.write(row); }","typeGuard":"boolean isWritable(DiskRowWriter w) { return w != null && !w.hasBeenClosed(); }","tryCatchPattern":"try { writer.write(row); } catch (IllegalStateException e) { writer = new DiskRowWriter(file, bufferSize); writer.write(row); }","preventionTips":["Treat writers as single-use; create a new one after close","Remove closed writers from pools or mark them invalid","Enforce lifecycle with try-with-resources style ownership","Never retry writes on the same writer instance after close"],"tags":["java","io","lifecycle","illegal-state"],"backgroundTag":"invalid-state-transition","analyzedSha":"65f8d8beb752f935752f2a0eec0ab017facab9ef","analyzedAt":"2026-09-11T00:12:21.696Z","contentChangedAt":"2026-09-11T00:12:21.696Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}