pentaho/pentaho-kettle · error · KettleException

Unable to read file

Error message

Unable to read file '<KETTLE_VARIABLES_FILE>'

What it means

After locating kettleVariables.xml, KettleVariablesList.init() parses it with XMLHandler; any exception during reading/parsing is wrapped in a KettleException 'Unable to read file ...'. Unlike error 631 the resource was found but its content could not be read or parsed.

Solutions

  1. Open kettleVariables.xml on the classpath and validate it is well-formed XML with <kettle-variables>/<kettle-variable> nodes.
  2. Check e.getCause() to distinguish IO failure from parse failure.
  3. Replace the corrupted file with one from a pristine kettle-engine artifact of the matching version.
  4. Ensure init() is only called once and no other code consumed the same InputStream first.

Example fix

// before
KettleVariablesList.init(); // KettleException on bad XML
// after
try (InputStream in = KettleVariablesList.class.getResourceAsStream("/" + Const.KETTLE_VARIABLES_FILE)) {
  Document doc = XMLHandler.loadXMLFile(in, null, false, false); // pre-validate structure
} catch (Exception e) {
  throw new RuntimeException("kettleVariables.xml is corrupt: " + e.getMessage(), e);
}
KettleVariablesList.init();
Defensive patterns

Strategy: try-catch

Validate before calling

try (InputStream in = getClass().getResourceAsStream("/" + Const.KETTLE_VARIABLES_FILE)) {
  Document doc = XMLHandler.loadXMLFile(in, null, false, false);
  if (XMLHandler.getSubNode(doc, "kettle-variables") == null) throw new IllegalStateException("bad kettleVariables.xml");
}

Try / catch

try { KettleVariablesList.init(); } catch (KettleException e) { throw new RuntimeException("kettleVariables.xml unreadable: " + e.getCause(), e); }

Prevention

When it happens

Trigger: XMLHandler.loadXMLFile(inputStream,...) or the per-variable getTagValue calls throw during KettleVariablesList.init() — malformed XML, closed/IO-failing stream, unexpected DOM structure.

Common situations: A corrupted or truncated kettleVariables.xml in a custom build; the wrong file is first on the classpath (e.g. an old version); encoding issues; the stream was already consumed by a previous init attempt.

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/4413cafb34842477. Report an issue: GitHub.

Appendix: source

Thrown at engine/src/main/java/org/pentaho/di/core/KettleVariablesList.java:79

        inputStream = variablesList.getClass().getResourceAsStream( "/" + Const.KETTLE_VARIABLES_FILE );
      }
      if ( inputStream == null ) {
        throw new KettlePluginException( "Unable to find standard kettle variables definition file: " + Const.KETTLE_VARIABLES_FILE );
      }
      Document doc = XMLHandler.loadXMLFile( inputStream, null, false, false );
      Node varsNode = XMLHandler.getSubNode( doc, "kettle-variables" );
      int nrVars = XMLHandler.countNodes( varsNode, "kettle-variable" );
      for ( int i = 0; i < nrVars; i++ ) {
        Node varNode = XMLHandler.getSubNodeByNr( varsNode, "kettle-variable", i );
        String description = XMLHandler.getTagValue( varNode, "description" );
        String variable = XMLHandler.getTagValue( varNode, "variable" );
        String defaultValue = XMLHandler.getTagValue( varNode, "default-value" );

        variablesList.getDescriptionMap().put( variable, description );
        variablesList.getDefaultValueMap().put( variable, defaultValue );
      }
    } catch ( Exception e ) {
      throw new KettleException( "Unable to read file '" + Const.KETTLE_VARIABLES_FILE + "'", e );
    } finally {
      if ( inputStream != null ) {
        try {
          inputStream.close();
        } catch ( IOException e ) {
          // we do not able to close property file will log it
          logger.logDetailed( "Unable to close file kettle variables definition file", e );
        }
      }
    }
  }

  /**
   * @return A mapping between the name of a standard kettle variable and its description.
   */
  public Map<String, String> getDescriptionMap() {
    return descriptionMap;
  }

View on GitHub (pinned to f3058517a1)