pentaho/pentaho-kettle · error · org.pentaho.di.core.exception.KettleValueException
KettleValueException wrapping generic Exception while…
Error message
KettleValueException wrapping generic Exception while loading file content (no message)
What it means
The full loadFileContentInBinary deliberately rethrows KettleFileNotFoundException (honoring failIfNoFile), but any OTHER exception while reading the file (VFS IOException, closed stream, encoding errors) is wrapped in a message-less KettleValueException(e). The cause carries the real problem; the message itself is empty.
Solutions
- Log/print e.getCause() to get the real underlying IOException
- Check file read permissions for the user running the transformation
- Validate the VFS URL/scheme and credentials for remote files
- Pre-check file.canRead() / exists() before the call
Example fix
// before
Object content = ValueDataUtil.loadFileContentInBinary(bowl, metaA, dataA, true);
// after
try {
Object content = ValueDataUtil.loadFileContentInBinary(bowl, metaA, dataA, true);
} catch (KettleValueException e) {
log.error("File content load failed: " + e.getCause(), e);
throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
// Java: verify readability before the call FileObject f = KettleVFS.getFileObject(metaA.getString(dataA)); if (f == null || !f.exists()) throw new FileNotFoundException(...); if (!f.isReadable()) throw new AccessDeniedException(f.getName().getPath());
Try / catch
try {
content = ValueDataUtil.loadFileContentInBinary(bowl, metaA, dataA, failIfNoFile);
} catch (KettleValueException e) {
Throwable cause = e.getCause(); // the real IOException lives here
log.error("File content load failed: " + (cause == null ? "unknown" : cause.getMessage()), cause);
throw e;
} Prevention
- Always inspect getCause() — the KettleValueException message is empty
- Run the transformation under a user with read access to target files
- Validate VFS URLs (scheme, credentials) for remote file systems
- Set failIfNoFile=false only when missing files are an expected, handled case
When it happens
Trigger: Calling loadFileContentInBinary(bowl, metaA, dataA, failIfNoFile) where the file exists but cannot be read: VFS provider error, permission denied, stream closed, or out-of-memory on huge files.
Common situations: Permission-restricted files in production; VFS misconfiguration (bad scheme/auth for sftp/http files); reading files locked by another process.
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
- Cannot open control file
- Cannot open data file
- CubeInputMeta.Exception.ErrorOpeningOrReadingCubeFile
- AbsSecurityManager.ERROR_0004_UNABLE_TO_APPLY_LOGICAL_ROLES_TO_RUNTIME_ROLE
- Calculator.ErrorInStepRunning
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/823d535ed6234e6d.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/org/pentaho/di/core/row/ValueDataUtil.java:714
byte[] content = null;
FileObject file = null;
InputStream is = null;
try {
file = KettleVFS.getInstance( bowl ).getFileObject( dataA.toString() );
throwsErrorOnFileNotFound( file );
is = KettleVFS.getInputStream( file );
int fileSize = (int) file.getContent().getSize();
content = Const.createByteArray( fileSize );
is.read( content, 0, fileSize );
} catch ( KettleFileNotFoundException e ) {
if ( failIfNoFile ) {
throw e;
}
log.debug( e.getMessage() );
} catch ( Exception e ) {
throw new KettleValueException( e );
} finally {
IOUtils.closeQuietly( file );
IOUtils.closeQuietly( is );
}
return content;
}
public static Object minus( ValueMetaInterface metaA, Object dataA, ValueMetaInterface metaB, Object dataB ) throws KettleValueException {
if ( dataA == null || dataB == null ) {
return null;
}
switch ( metaA.getType() ) {
case ValueMetaInterface.TYPE_NUMBER:
return new Double( metaA.getNumber( dataA ).doubleValue() - metaB.getNumber( dataB ).doubleValue() );
case ValueMetaInterface.TYPE_INTEGER:
return new Long( metaA.getInteger( dataA ).longValue() - metaB.getInteger( dataB ).longValue() );
case ValueMetaInterface.TYPE_BIGNUMBER:View on GitHub (pinned to f3058517a1)