chinabugotech/hutool · error · IOException

Writer is closed!{}

Error message

Writer is closed!{}

What it means

AppendableWriter wraps any Appendable as a java.io.Writer. After close() runs, the private 'closed' flag becomes true and every subsequent write/append/flush call hits checkNotClosed(), which throws IOException("Writer is closed!"). This is a standard use-after-close guard mirroring JDK stream behavior.

Source

Thrown at hutool-core/src/main/java/cn/hutool/core/io/AppendableWriter.java:94

		appendable.append(CharBuffer.wrap(cbuf));
	}

	@Override
	public void flush() throws IOException {
		checkNotClosed();
		if (flushable) {
			((Flushable) appendable).flush();
		}
	}

	/**
	 * 检查Writer是否已经被关闭
	 *
	 * @throws IOException IO异常
	 */
	private void checkNotClosed() throws IOException {
		if (closed) {
			throw new IOException("Writer is closed!" + this);
		}
	}

	@Override
	public void close() throws IOException {
		if (false == closed) {
			flush();
			if (appendable instanceof Closeable) {
				((Closeable) appendable).close();
			}
			closed = true;
		}
	}
}

View on GitHub (pinned to 8870454b2a)

Solutions

  1. Do not reuse the AppendableWriter after close() — create a fresh instance backed by a new Appendable.
  2. Track the lifecycle yourself and stop issuing write calls once you have closed the writer.
  3. Move the close() to the true end of the writer's lifetime (outermost try-with-resources) so no write can follow it.

Example fix

// before: writer closed inside loop then reused
writer.append(line);
writer.close();
writer.append(nextLine); // -> IOException: Writer is closed!

// after: close once, after all writes
try (AppendableWriter w = new AppendableWriter(sb)) {
    w.append(line);
    w.append(nextLine);
}
Defensive patterns

Strategy: validation

Validate before calling

// Track ownership of the writer in the caller; never write after close.
// AppendableWriter has no isOpen() accessor, so manage it externally:
AppendableWriter w = new AppendableWriter(sb);
boolean closed = false;
try {
    w.append(line);
} finally {
    w.close();
    closed = true;
}
// guard any deferred write
if (!closed) { w.append(more); }

Try / catch

try {
    writer.append(text);
} catch (IOException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Writer is closed!")) {
        // writer was already closed: create a new one or skip
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Calling write(), append(), or flush() on an AppendableWriter instance after close() has already been invoked on it.

Common situations: Sharing a writer across methods where one path closes it in a finally/try-with-resources and another path later writes to it; pooling/reusing writer instances; closing in an exception handler then retrying the write.

Related errors


AI-assisted analysis of chinabugotech/hutool@8870454b2a (2026-08-14). Data as JSON: /api/errors/a4f9b4c047c23127. Report an issue: GitHub.