pentaho/pentaho-kettle · error · KettleException

Cannot open control file

Error message

Cannot open control file [path=${controlFile}]

What it means

invokeLoadingControlFile opens the fastload control file with FileUtils.openInputStream; an IOException there (file missing, unreadable, path is a directory) is wrapped as 'Cannot open control file [path=...]'. The control file holds the FastLoad script and must be readable before its content is piped to the running fastload process.

Solutions

  1. Verify the control file path resolves and exists: ls -l <resolved-path>; regenerate the control file if it was deleted.
  2. Fix variable substitution: log or print resolveFileName(meta.getControlFile().getValue()) and confirm the ${VARIABLE} values at runtime.
  3. Grant read permission on the control file and its parent directory to the Kettle run user.
  4. Confirm the path points to a file, not a directory, and uses OS-appropriate separators.
  5. If the control file is expected to be auto-generated by TeraFast, enable the generation option or run the prerequisite step first.

Example fix

// before
control = FileUtils.openInputStream( controlFile );
// after
if ( !controlFile.isFile() || !controlFile.canRead() ) {
  throw new KettleException( "Control file missing or unreadable: " + controlFile.getAbsolutePath() ); // fail with actionable message
}
control = FileUtils.openInputStream( controlFile );
Defensive patterns

Strategy: validation

Validate before calling

import java.io.File;
String resolved = resolveFileName( controlFileValue );
File cf = new File( resolved );
if ( !cf.exists() ) throw new IllegalStateException( "Control file does not exist: " + cf.getAbsolutePath() );
if ( !cf.isFile() ) throw new IllegalStateException( "Control file path is not a file: " + cf.getAbsolutePath() );
if ( !cf.canRead() ) throw new IllegalStateException( "Control file not readable by current user: " + cf.getAbsolutePath() );

Type guard

boolean isReadableFile( String path ) {
  File f = new File( path );
  return f.isFile() && f.canRead();
}

Try / catch

try {
  control = FileUtils.openInputStream( controlFile );
  controlContent = environmentSubstitute( FileUtils.readFileToString( controlFile ) );
} catch ( IOException e ) {
  throw new KettleException( "Cannot open control file [path=" + controlFile.getAbsolutePath()
    + "]; verify the file exists, is readable, and variables resolve correctly", e );
}

Prevention

When it happens

Trigger: execute() -> invokeLoadingControlFile(): meta.getControlFile().getValue() resolves (after resolveFileName) to a non-existent file, a directory, or a file the current OS user cannot read, so FileUtils.openInputStream/readFileToString throws IOException.

Common situations: Control file was never generated (e.g. 'generate control file' option disabled but a path still configured); typo or wrong variable value in the control file path; file generated on another host/agent; permission tightened after generation; path uses Windows separators on Linux.

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


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

Appendix: source

Thrown at plugins/terafast-bulk-loader/impl/src/main/java/org/pentaho/di/trans/steps/terafastbulkloader/TeraFast.java:367

    }
  }

  /**
   * Invoke loading with control file.
   *
   * @throws KettleException
   *           ...
   */
  private void invokeLoadingControlFile() throws KettleException {
    File controlFile = null;
    final InputStream control;
    final String controlContent;
    try {
      controlFile = new File( resolveFileName( this.meta.getControlFile().getValue() ) );
      control = FileUtils.openInputStream( controlFile );
      controlContent = environmentSubstitute( FileUtils.readFileToString( controlFile ) );
    } catch ( IOException e ) {
      throw new KettleException( "Cannot open control file [path=" + controlFile + "]", e );
    }
    try {
      IOUtils.write( controlContent, this.fastload );
      this.fastload.flush();
    } catch ( IOException e ) {
      throw new KettleException( "Cannot pipe content of control file to fastload [path=" + controlFile + "]", e );
    } finally {
      IOUtils.closeQuietly( control );
      IOUtils.closeQuietly( this.fastload );
    }
  }

  /**
   * Invoke loading with loading commands.
   *
   * @throws KettleException
   *           ...
   */

View on GitHub (pinned to f3058517a1)