{"record":{"id":"9fa812af9d9362a9","repo":"pentaho/pentaho-kettle","slug":"unable-to-create-a-logging-event-listener-to-write-to-file","errorCode":null,"errorMessage":"Unable to create a logging event listener to write to file '${filename}'","messagePattern":"Unable to create a logging event listener to write to file '(.+?)'","errorType":"exception","errorClass":"KettleException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/pentaho/di/core/logging/FileLoggingEventListener.java","lineNumber":72,"sourceCode":"   * file.\n   *\n   * @param logChannelId\n   * @param filename\n   * @param append\n   * @throws KettleException\n   */\n  public FileLoggingEventListener( String logChannelId, String filename, boolean append ) throws KettleException {\n    this.logChannelId = logChannelId;\n    this.filename = filename;\n    this.layout = new KettleLogLayout( true );\n    this.exception = null;\n\n    file = KettleVFS.getInstance( DefaultBowl.getInstance() ).getFileObject( filename );\n    outputStream = null;\n    try {\n      outputStream = KettleVFS.getInstance( DefaultBowl.getInstance() ).getOutputStream( file, append );\n    } catch ( Exception e ) {\n      throw new KettleException(\n        \"Unable to create a logging event listener to write to file '\" + filename + \"'\", e );\n    }\n  }\n\n  @Override\n  public void eventAdded( KettleLoggingEvent event ) {\n\n    try {\n      Object messageObject = event.getMessage();\n      if ( messageObject instanceof LogMessage ) {\n        boolean logToFile = false;\n\n        if ( logChannelId == null ) {\n          logToFile = true;\n        } else {\n          LogMessage message = (LogMessage) messageObject;\n          // This should be fast enough cause cached.\n          List<String> logChannelChildren = LoggingRegistry.getInstance().getLogChannelChildren( logChannelId );","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/core/src/main/java/org/pentaho/di/core/logging/FileLoggingEventListener.java#L54-L90","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nnew FileLoggingEventListener(\"logs/kettle.log\", true); // logs/ missing\n// after\nFile logDir = new File(\"logs\");\nlogDir.mkdirs();\nnew FileLoggingEventListener(logDir.getAbsolutePath() + \"/kettle.log\", true);","handlingStrategy":"try-catch","validationCode":"File f = new File(filename);\nif (f.isDirectory() || (f.exists() && !f.canWrite())) throw new IllegalStateException(\"Cannot write log file: \" + filename);\nFile parent = f.getAbsoluteFile().getParentFile();\nif (parent != null) parent.mkdirs();","typeGuard":"static boolean canOpenForWrite(String path) {\n  try (java.io.OutputStream os = new java.io.FileOutputStream(path, true)) { return true; }\n  catch (Exception e) { return false; }\n}","tryCatchPattern":"try {\n  FileLoggingEventListener listener = new FileLoggingEventListener(filename, true);\n  KettleLogStore.getAppender().addLoggingEventListener(listener);\n} catch (KettleException e) {\n  log.logError(\"Could not open log file listener: \" + e.getCause(), e);\n}","preventionTips":["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."],"tags":["kettle","logging","vfs","file-io"],"backgroundTag":"file-open-failed","analyzedSha":"f3058517a153da500bf4551f46d79b91bf8ec552","analyzedAt":"2026-09-13T14:04:16.340Z","contentChangedAt":"2026-09-13T14:04:16.340Z","schemaVersion":2},"datasetVersion":"2026-09-20T23:17:15.980Z"}