pentaho/pentaho-kettle · error · KettleException

JobEntrySetVariables.Error.UnableReadPropertiesFile

Error message

JobEntrySetVariables.Error.UnableReadPropertiesFile

What it means

This KettleException is thrown in execute() when reading the properties file that supplies variable names/values fails. The entry loads a .properties file (filename after environment substitution) to define variables; any exception during load is replaced with the localized JobEntrySetVariables.Error.UnableReadPropertiesFile message naming the file. Note the original exception is not chained.

Solutions

  1. Verify the file exists and is readable at the exact resolved path on the machine running the job (log realFilename)
  2. Check that any variables used in the filename are defined in kettle.properties or passed at runtime
  3. If the filename uses ${Internal.Transformation.Filename.Directory}-style relative paths, confirm the job's location context
  4. Fix encoding/syntax problems in the properties file (ISO-8859-1 expected by Properties.load)

Example fix

// before
// Filename field: ${CONFIG_DIR}/app.properties  (CONFIG_DIR unset on server)
// after
// define in ~/.kettle/kettle.properties:
CONFIG_DIR=/opt/pdi/config
// or use an absolute path: /opt/pdi/config/app.properties
Defensive patterns

Strategy: validation

Validate before calling

// before running the job, verify the resolved properties file
String path = job.environmentSubstitute("${CONFIG_DIR}/app.properties");
File pf = new File(path);
if (!pf.isFile() || !pf.canRead()) {
  throw new IllegalStateException("Properties file not readable: " + path);
}

Try / catch

try {
  result = jobEntry.execute(result, nr);
} catch (KettleException e) {
  if (e.getMessage().contains("UnableReadPropertiesFile")) {
    logError("Check properties file path/permissions on the executing node: " + e.getMessage());
  }
}

Prevention

When it happens

Trigger: Executing the entry with 'File' variable source where realFilename points to a missing, unreadable, or malformed properties file, or the file cannot be opened by Properties.load (IO error, bad encoding, path is a directory).

Common situations: Typo in filename or wrong path on the execution node (file exists only on the dev machine); missing environment variable in the filename path; agent running with a different working directory; properties file with invalid characters/encoding; file permissions.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


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

Appendix: source

Thrown at engine/src/main/java/org/pentaho/di/job/entries/setvariables/JobEntrySetVariables.java:243

      List<String> variableValues = new ArrayList<String>();
      List<Integer> variableTypes = new ArrayList<Integer>();

      String realFilename = environmentSubstitute( filename );
      if ( !Utils.isEmpty( realFilename ) ) {
        try ( InputStream is = KettleVFS.getInstance( parentJobMeta.getBowl() ).getInputStream( realFilename );
            // for UTF8 properties files
            InputStreamReader isr = new InputStreamReader( is, "UTF-8" );
            BufferedReader reader = new BufferedReader( isr );
            ) {
          Properties properties = new Properties();
          properties.load( reader );
          for ( Map.Entry<Object, Object> entry : properties.entrySet() ) {
            variables.add( (String) entry.getKey() );
            variableValues.add( (String) entry.getValue() );
            variableTypes.add( fileVariableType );
          }
        } catch ( Exception e ) {
          throw new KettleException( BaseMessages.getString(
            PKG, "JobEntrySetVariables.Error.UnableReadPropertiesFile", realFilename ) );
        }
      }

      if ( variableName != null ) {
        for ( int i = 0; i < variableName.length; i++ ) {
          if ( ( variables.contains( variableName[ i ] ) && replaceVars ) || !variables.contains(
            variableName[ i ] ) ) {
            variables.add( variableName[ i ] );
            variableValues.add( variableValue[ i ] );
            variableTypes.add( variableType[ i ] );
          }
        }
      }

      // if parentJob exists - clear/reset all entrySetVariables before applying the actual ones
      if ( parentJob != null ) {
        for ( String key : getEntryStepSetVariablesMap().keySet() ) {

View on GitHub (pinned to f3058517a1)