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
- Open kettleVariables.xml on the classpath and validate it is well-formed XML with <kettle-variables>/<kettle-variable> nodes.
- Check e.getCause() to distinguish IO failure from parse failure.
- Replace the corrupted file with one from a pristine kettle-engine artifact of the matching version.
- 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
- Validate the XML with a parser/linter before shipping custom builds
- Never share one InputStream across multiple init calls
- Keep the resource file byte-identical to the official distribution
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
- DimensionLookupMeta.Exception.UnableToLoadStepInfoFromXML
- Error loading transformation step from XML
- Error loading transformation step from XML
- NullIfMeta.Exception.UnableToReadStepInfoFromXML
- RepositoryMeta.Error.ReadingInfo
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)