pentaho/pentaho-kettle · error · IOException
Already closed
Error message
Already closed
What it means
JCRFileOutputStream.close writes the buffered data to the repository via client.writeData. If close() is invoked a second time after the stream was already closed, it throws an IOException wrapping an IllegalStateException('Already closed'). This guards against double-write of the stream's buffer to the repository.
Solutions
- Remove duplicate close() calls; rely on a single close path (prefer try-with-resources alone)
- Check the stream's own guard if you must double-close defensively
- Wrap close() in an ignored-IOException guard only when the close is best-effort
Example fix
// before
stream.close();
...
stream.close(); // second close throws 'Already closed'
// after
stream.close();
...
if ( !stream.isClosed() ) { stream.close(); } // or remove the duplicate close entirely Defensive patterns
Strategy: try-catch
Validate before calling
// guard before closing defensively
boolean streamIsOpen( OutputStream s ) { return s != null && !( s instanceof JCRFileOutputStream j && j.isClosed() ); } Type guard
boolean canClose( OutputStream s ) {
return s instanceof JCRFileOutputStream && !((JCRFileOutputStream) s).isClosed();
} Try / catch
try ( OutputStream out = client.getOutputStream( name ) ) {
out.write( data );
} catch ( IOException e ) {
if ( e.getCause() instanceof IllegalStateException
&& "Already closed".equals( e.getCause().getMessage() ) ) {
log.debug( "Stream already closed; ignoring" );
} else {
throw e;
}
} Prevention
- Use a single close path: try-with-resources only, no manual close() in finally
- Never cache or reuse output stream objects after committing data
- Check closed state before defensive closes in utility code
When it happens
Trigger: Calling close() twice on the same JCRFileOutputStream, or code paths (e.g. try-with-resources plus an explicit close in a finally block) that close the stream more than once.
Common situations: try-with-resources combined with a manual close(); utility code that closes streams defensively; reusing a cached output stream reference after it has been committed.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- Already closed
- Error while closing output
- Error writing marker flag
- Not a valid input stream!
- <toString()> : Unable to read value metadata from input…
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/20643dca940221f1.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/repo-vfs/repo-vfs-ws/src/main/java/org/pentaho/di/plugins/repovfs/ws/vfs/JCRFileOutputStream.java:44
*/
public class JCRFileOutputStream extends ByteArrayOutputStream {
private static final Logger log = LoggerFactory.getLogger( JCRFileOutputStream.class );
private final RepositoryClient client;
private final String[] name;
private boolean closed = false;
public JCRFileOutputStream( String[] fileName, RepositoryClient client ) {
this.name = fileName;
this.client = client;
}
@Override
public void close() throws IOException {
if ( closed ) {
throw new IOException( new IllegalStateException( "Already closed" ) );
}
closed = true;
try ( ByteArrayInputStream bais = new ByteArrayInputStream( toByteArray() ) ) {
client.writeData( name, bais );
log.debug( "data written" );
} catch ( RepositoryClientException e ) {
throw new IOException( e );
}
}
}
View on GitHub (pinned to f3058517a1)