pentaho/pentaho-kettle · error · IllegalStateException
S3FileOutput.Error.S3ClientInitFailed
Error message
S3FileOutput.Error.S3ClientInitFailed
What it means
processS3Path throws IllegalStateException with message key 'S3FileOutput.Error.S3ClientInitFailed' when the S3 provider returns a null AmazonS3 client after prepare(). A null client means the AWS SDK client could not be constructed, typically because credentials or region configuration are missing/invalid.
Solutions
- Set valid AWS access key and secret key in the S3 File Output step (or fix the credentials source: env vars, profile, IAM role).
- Verify the AWS region is configured and correct for the bucket.
- Check that s3Provider.prepare() gets complete S3Details (bucket, path, credentials, variables resolved) before requesting the client.
- Test credentials with AWS CLI (aws sts get-caller-identity) on the same host to rule out environment issues.
Example fix
// before
AmazonS3 s3Client = s3Provider.getS3Client( s3Details );
if ( s3Client == null ) {
throw new IllegalStateException( BaseMessages.getString( PKG, "S3FileOutput.Error.S3ClientInitFailed" ) );
}
// after: fail fast with a clearer message when credentials are absent
if ( s3Details.getAccessKey() == null || s3Details.getSecretKey() == null ) {
throw new IllegalStateException( "AWS credentials are not configured for the S3 File Output step" );
}
AmazonS3 s3Client = s3Provider.getS3Client( s3Details ); Defensive patterns
Strategy: validation
Validate before calling
// verify credentials before invoking processS3Path boolean credsReady = awsAccessKey != null && !awsAccessKey.isEmpty() && awsSecretKey != null && !awsSecretKey.isEmpty(); if ( !credsReady ) throw new IllegalStateException( "Configure AWS access/secret keys before running" );
Try / catch
try {
helper.processS3Path( transMeta, params, path );
} catch ( IllegalStateException e ) {
logError( "S3 client init failed: " + e.getMessage() );
} Prevention
- Configure AWS keys or a valid credential chain (env, profile, IAM role)
- Set the correct AWS region
- Run aws sts get-caller-identity to verify host credentials
- Re-test the connection from the step dialog after changes
When it happens
Trigger: listS3ContentsAction or testProcessS3PathSuccess -> processS3Path where createS3DetailsFromParams yields credentials (access key/secret) that s3Provider.prepare()/getS3Client() reject, so getS3Client returns null instead of a client.
Common situations: Empty or malformed AWS access/secret keys in the step dialog; environment without AWS credentials and no keys configured; wrong region name; IAM profile not available on the host; AWS SDK configuration changes across plugin versions.
Related errors
- FileSystemException wrapping SdkClientException
- vfs.provider/get-type.error
- vfs.provider/get-type.error
- vfs.provider.local/create-folder.error
- vfs.provider.s3/transfer.error
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/8db853c86beb9322.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/s3-vfs/core/src/main/java/org/pentaho/amazon/s3/S3FileOutputHelper.java:295
} catch ( Exception e ) {
response.put( ERROR,
BaseMessages.getString( PKG, "S3FileOutput.Error.ListObjectsFailed" ) );
response.put( ACTION_STATUS, FAILURE_RESPONSE );
}
return response;
}
public void processS3Path( TransMeta transMeta,
Map<String, String> queryParams,
String path,
JSONArray contents ) throws KettleException {
String s3Prefix = S3FileProvider.SCHEME + "://";
S3Details s3Details = createS3DetailsFromParams( transMeta, queryParams );
s3Details.setSpace( new Variables() );
s3Details = s3Provider.prepare( s3Details );
AmazonS3 s3Client = s3Provider.getS3Client( s3Details );
if ( s3Client == null ) {
throw new IllegalStateException(
BaseMessages.getString( PKG, "S3FileOutput.Error.S3ClientInitFailed" )
);
}
String cleanPath = path.replace( s3Prefix, "" );
String bucketName = cleanPath.contains( S3FileName.DELIMITER )
? cleanPath.substring( 0, cleanPath.indexOf( S3FileName.DELIMITER ) )
: cleanPath;
String prefix = cleanPath.contains( S3FileName.DELIMITER )
? cleanPath.substring( cleanPath.indexOf( S3FileName.DELIMITER ) + 1 )
: "";
if ( !prefix.isEmpty() && !prefix.endsWith( S3FileName.DELIMITER ) ) {
prefix += S3FileName.DELIMITER;
}
ListObjectsV2Request listRequest = new ListObjectsV2Request()
.withBucketName( bucketName )
.withPrefix( prefix )
.withDelimiter( S3FileName.DELIMITER );View on GitHub (pinned to f3058517a1)