pentaho/pentaho-kettle · error · KettleException

We can not find file []!

Error message

We can not find file []!

What it means

Database.execStatementsFromFile() (execSqlFile path) throws this when the SQL script file resolved via KettleVFS does not exist on the filesystem/VFS layer. It is thrown after the filename emptiness check, so the name was provided but nothing exists at that path. The library deliberately fails fast instead of proceeding to open an input stream.

Solutions

  1. Verify the file exists at the exact resolved path (ls/cat or VFS listing) before running the transformation.
  2. Convert relative paths to absolute, ideally using kettle environment variables like ${Internal.Job.Filename.Directory} to build the path.
  3. Check for typos, case sensitivity, and Windows vs Unix path separators.
  4. Ensure the file is deployed to every execution node when running clustered.
  5. If the file is intentionally optional, check existence (KettleVFS.getFileObject(f).exists()) before invoking.

Example fix

// before
database.execStatementsFromFile(logChannel, sqlFilePath, false, true, null, charset);
// after
FileObject f = KettleVFS.getInstance(bowl).getFileObject(sqlFilePath);
if (f == null || !f.exists()) { throw new IllegalStateException("SQL file missing: " + sqlFilePath); }
database.execStatementsFromFile(logChannel, sqlFilePath, false, true, null, charset);
Defensive patterns

Strategy: validation

Validate before calling

FileObject f = KettleVFS.getInstance(bowl).getFileObject(sqlFilePath);
if (Utils.isEmpty(sqlFilePath) || f == null || !f.exists()) {
  throw new IllegalArgumentException("SQL file not found: " + sqlFilePath);
}

Type guard

boolean sqlFileExists(String path) {
  try { FileObject f = KettleVFS.getInstance(new Bowl()).getFileObject(path); return f != null && f.exists(); }
  catch (Exception e) { return false; }
}

Try / catch

try {
  database.execStatementsFromFile(logChannel, path, false, true, null, charset);
} catch (KettleException e) {
  if (e.getMessage() != null && e.getMessage().startsWith("We can not find file")) {
    // resolve absolute path, check deployment, retry once with corrected path
  } else { throw e; }
}

Prevention

When it happens

Trigger: Calling Database.execStatementsFromFile (or SQL execution from file) with a filename that is non-empty but points to a missing file — wrong absolute path, file deleted before execution, or VFS scheme/URI resolution pointing elsewhere.

Common situations: Job/transformation configuration references an .sql file relative to a working directory that differs at runtime; file lives in a repo but not on the execution node; path uses Windows-style separators or unexpanded variables like ${Internal.Job.Filename.Directory}.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13). Data as JSON: /api/errors/3865fbee5132da59. Report an issue: GitHub.

Appendix: source

Thrown at core/src/main/java/org/pentaho/di/core/database/Database.java:5294

   * Execute an SQL statement inside a file on the database connection (has to be open)
   *
   * @param filename The file that contains SQL to execute
   * @return a Result object indicating the number of lines read, deleted, inserted, updated, ...
   * @throws KettleDatabaseException in case anything goes wrong.
   * @sendSinglestatement send one statement
   */
  public Result execStatementsFromFile( Bowl bowl, String filename, boolean sendSinglestatement )
    throws KettleException {
    FileObject sqlFile = null;
    InputStream is = null;
    InputStreamReader bis = null;
    try {
      if ( Utils.isEmpty( filename ) ) {
        throw new KettleException( "Filename is missing!" );
      }
      sqlFile = KettleVFS.getInstance( bowl ).getFileObject( filename );
      if ( !sqlFile.exists() ) {
        throw new KettleException( "We can not find file [" + filename + "]!" );
      }

      is = KettleVFS.getInputStream( sqlFile );
      bis = new InputStreamReader( new BufferedInputStream( is, 500 ) );

      BufferedReader buff = new BufferedReader( bis );
      String sLine;
      StringBuilder sql = new StringBuilder( Const.CR );

      while ( ( sLine = buff.readLine() ) != null ) {
        if ( Utils.isEmpty( sLine ) ) {
          sql.append( Const.CR );
        } else {
          sql.append( Const.CR ).append( sLine );
        }
      }

      if ( sendSinglestatement ) {

View on GitHub (pinned to f3058517a1)