pentaho/pentaho-kettle · error · KettleException

Could not read file

Error message

Could not read file 

What it means

S3Provider.prepare() reads an optional credentials file line by line and stores its contents on S3VfsDetails. If the file cannot be read, it wraps the IOException in a KettleException with the message 'Could not read file '. This is a fail-fast configuration error: the S3 connection cannot be prepared without the credentials file.

Solutions

  1. Check the credentials-file path configured on the S3 connection and fix typos.
  2. Verify the file exists and is readable by the user running Pentaho (chmod/chown).
  3. Use an absolute path rather than a relative one, since the working directory varies.
  4. Alternatively configure access/secret keys directly instead of a credentials file.
  5. Catch KettleException at the call site to surface a user-friendly message.

Example fix

// before
s3Details.setCredentialsFile( "/opt/creds.txt" );
// after
File f = new File( "/opt/creds.txt" );
if ( !f.isFile() || !f.canRead() ) {
  throw new KettleException( "Credentials file missing or unreadable: " + f.getAbsolutePath() );
}
Defensive patterns

Strategy: validation

Validate before calling

java.io.File f = new java.io.File( credentialsFilePath );
if ( credentialsFilePath == null || credentialsFilePath.isEmpty() )
  throw new IllegalArgumentException( "credentials file path not set" );
if ( !f.isFile() ) throw new java.io.FileNotFoundException( f.getAbsolutePath() );
if ( !f.canRead() ) throw new java.io.IOException( "not readable: " + f.getAbsolutePath() );

Try / catch

try {
  provider.prepare();
} catch ( KettleException e ) {
  // e.getCause() is the IOException from reading the credentials file
  throw new KettleException( "Fix the credentials-file path on the S3 connection: " + e.getCause().getMessage(), e );
}

Prevention

When it happens

Trigger: Calling prepare() when the credentials-file path set on s3Details points to a nonexistent, unreadable, locked, or permission-denied file, or when the BufferedReader/FileInputStream construction throws IOException.

Common situations: Typo in the credentials file path in the S3 VFS connection dialog, file deployed on a different node, file mounted with wrong permissions, or file deleted between configuration and runtime.

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/98a928afdb8eeb74. Report an issue: GitHub.

Appendix: source

Thrown at plugins/s3-vfs/core/src/main/java/org/pentaho/amazon/s3/provider/S3Provider.java:200

    } finally {
      Thread.currentThread().setContextClassLoader( cl );
    }
  }

  @Override public S3Details prepare( S3Details s3Details ) throws KettleException {
    VariableSpace space = getSpace( s3Details );
    if ( s3Details.getAuthType().equals( CREDENTIALS_FILE ) ) {
      String credentialsFilePath = getVar( s3Details.getCredentialsFilePath(), space );
      if ( credentialsFilePath != null ) {
        try ( BufferedReader reader = Files.newBufferedReader( Paths.get( credentialsFilePath ) ) ) {
          StringBuilder builder = new StringBuilder();
          String currentLine;
          while ( ( currentLine = reader.readLine() ) != null ) {
            builder.append( currentLine ).append( "\n" );
          }
          s3Details.setCredentialsFile( builder.toString() );
        } catch ( IOException e ) {
          throw new KettleException( "Could not read file ", e );
        }
      }
    }
    return s3Details;
  }

  @Override
  public FileObject getDirectFile( Bowl bowl, S3Details s3Conn, String path ) throws KettleFileException {
    if ( !S3FileProvider.SCHEME.equals( s3Conn.getType() ) ) {
      return null;
    }
    FileSystemOptions fsopts = getOpts( s3Conn );
    S3CommonFileSystemConfigBuilder builder = new S3CommonFileSystemConfigBuilder( fsopts );
    // Disable "Use Defaults" so we don't call back into ConnectionManager for the default S3 connection
    builder.setUseDefaults( false );
    fsopts = builder.getFileSystemOptions();

    String uri = S3FileProvider.SCHEME + "://" + path;

View on GitHub (pinned to f3058517a1)