pentaho/pentaho-kettle · error · KettleException
Unable to create a logging event listener to write to file
Error message
Unable to create a logging event listener to write to file '${filename}' What it means
FileLoggingEventListener's constructor opens a VFS output stream to the given filename so log events can be appended to it. If KettleVFS cannot open that stream for any reason (bad path, locked file, filesystem error), it wraps the cause in a KettleException. The listener is therefore never usable and the caller gets this error at construction time.
Solutions
- Verify the filename is an absolute, valid path and the parent directory exists (create it first).
- Ensure the process has write permission on the target file/directory.
- Close any other process holding the file locked, or use a different filename.
- Inspect the wrapped cause (KettleException.getCause()) for the underlying VFS error.
Example fix
// before
new FileLoggingEventListener("logs/kettle.log", true); // logs/ missing
// after
File logDir = new File("logs");
logDir.mkdirs();
new FileLoggingEventListener(logDir.getAbsolutePath() + "/kettle.log", true); Defensive patterns
Strategy: try-catch
Validate before calling
File f = new File(filename);
if (f.isDirectory() || (f.exists() && !f.canWrite())) throw new IllegalStateException("Cannot write log file: " + filename);
File parent = f.getAbsoluteFile().getParentFile();
if (parent != null) parent.mkdirs(); Type guard
static boolean canOpenForWrite(String path) {
try (java.io.OutputStream os = new java.io.FileOutputStream(path, true)) { return true; }
catch (Exception e) { return false; }
} Try / catch
try {
FileLoggingEventListener listener = new FileLoggingEventListener(filename, true);
KettleLogStore.getAppender().addLoggingEventListener(listener);
} catch (KettleException e) {
log.logError("Could not open log file listener: " + e.getCause(), e);
} Prevention
- Use absolute paths and create parent directories before constructing the listener.
- Check write permissions for the service account on the log directory.
- Avoid log paths on shares that can be locked by other processes.
- Always remove the listener and call close() in a finally block.
When it happens
Trigger: new FileLoggingEventListener(filename, append) where KettleVFS.getFileObject succeeds but getOutputStream throws — e.g. the path points to a directory, the parent folder does not exist, the file is locked by another process, or no write permission.
Common situations: Configuring file-based logging with a typo'd or relative path that doesn't resolve; writing to a log file already held open exclusively by another job; running under a service account without write access to the log directory.
Understand the failure class
Background: "open() failed", "failed to open file", "cannot create file" — what a file open error means and how to fix it — this error's family across 42 libraries.
Related errors
- AvroInputDialog.Error.KettleFileException
- JobMeta.Exception.AnErrorOccuredReadingJob
- LoadFileInput.Error.GettingFileContent
- There was an error while trying to open file '' for writing
- Unable to close output of file
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/9fa812af9d9362a9.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/org/pentaho/di/core/logging/FileLoggingEventListener.java:72
* file.
*
* @param logChannelId
* @param filename
* @param append
* @throws KettleException
*/
public FileLoggingEventListener( String logChannelId, String filename, boolean append ) throws KettleException {
this.logChannelId = logChannelId;
this.filename = filename;
this.layout = new KettleLogLayout( true );
this.exception = null;
file = KettleVFS.getInstance( DefaultBowl.getInstance() ).getFileObject( filename );
outputStream = null;
try {
outputStream = KettleVFS.getInstance( DefaultBowl.getInstance() ).getOutputStream( file, append );
} catch ( Exception e ) {
throw new KettleException(
"Unable to create a logging event listener to write to file '" + filename + "'", e );
}
}
@Override
public void eventAdded( KettleLoggingEvent event ) {
try {
Object messageObject = event.getMessage();
if ( messageObject instanceof LogMessage ) {
boolean logToFile = false;
if ( logChannelId == null ) {
logToFile = true;
} else {
LogMessage message = (LogMessage) messageObject;
// This should be fast enough cause cached.
List<String> logChannelChildren = LoggingRegistry.getInstance().getLogChannelChildren( logChannelId );View on GitHub (pinned to f3058517a1)