pentaho/pentaho-kettle · error · FileSystemException

vfs.provider.s3/transfer.null-argument

vfs.provider.s3/transfer.null-argument

Error message

vfs.provider.s3/transfer.null-argument

What it means

Thrown by S3TransferManager.copy() when either the source or destination S3CommonFileObject is null, or its bucketName/key fields are null. The S3 copy API requires non-null bucket and key for both sides, so they are validated up front.

Solutions

  1. Null-check both FileObjects and confirm they are resolved S3 objects before calling copy
  2. Ensure bucketName and key are populated by resolving via the S3 VFS provider (s3://bucket/key)
  3. Log the two qualified names in the message to identify which argument is bad
  4. Fix the upstream code that produced an unresolved/null file object

Example fix

// before
transferManager.copy( src, dst );
// after
if ( src != null && dst != null && src.bucketName != null && src.key != null
  && dst.bucketName != null && dst.key != null ) {
  transferManager.copy( src, dst );
} else {
  throw new IllegalArgumentException( "src/dst must be resolved S3 file objects" );
}
Defensive patterns

Strategy: type-guard

Validate before calling

if ( src == null || dst == null
  || src.bucketName == null || src.key == null
  || dst.bucketName == null || dst.key == null ) {
  throw new IllegalArgumentException( "both src and dst must be resolved s3://bucket/key objects" );
}

Type guard

boolean isResolvedS3File( FileObject f ) {
  return f instanceof S3CommonFileObject
    && ((S3CommonFileObject) f).bucketName != null
    && ((S3CommonFileObject) f).key != null;
}

Try / catch

try {
  transferManager.copy( src, dst );
} catch ( FileSystemException e ) {
  if ( "vfs.provider.s3/transfer.null-argument".equals( e.getMessage() ) ) {
    // inspect the two names in the message to see which side was null
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling transferManager.copy(src, dst) with a null object, or with a FileObject whose bucketName/key were never populated (e.g. a non-S3 or unresolved file object).

Common situations: Resolving a VFS URI that failed silently and passing the result on; passing a file from a different filesystem whose fields are null; wiring bugs where the destination is created but never resolved.

Related errors


AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13). Data as JSON: /api/errors/24a6a001bf8d34d0. Report an issue: GitHub.

Appendix: source

Thrown at plugins/s3-vfs/core/src/main/java/org/pentaho/s3common/S3TransferManager.java:57

  }

  public TransferManager getTransferManager() {
    return transferManager;
  }

  /**
   * Perform S3->S3 multipart copy with a custom thread pool size.
   *
   * @param src           Source S3FileObject
   * @param dst           Destination S3FileObject
   * @param logger        Logger for logging
   * @throws FileSystemException if copy fails
   */
  public void copy( S3CommonFileObject src, S3CommonFileObject dst ) throws FileSystemException {
    if ( src == null || dst == null
      || src.bucketName == null || src.key == null
      || dst.bucketName == null || dst.key == null ) {
      throw new FileSystemException( "vfs.provider.s3/transfer.null-argument",
        src != null ? src.getQualifiedName() : "null",
        dst != null ? dst.getQualifiedName() : "null" );
    }
    try {
      Copy copy = getTransferManager().copy(
        src.bucketName, src.key,
        dst.bucketName, dst.key
      );
      copy.waitForCompletion();
      logger.info( "S3->S3 server-side copy succeeded: {} -> {}",
                   src.getQualifiedName(), dst.getQualifiedName() );
    } catch ( InterruptedException ie ) {
      Thread.currentThread().interrupt();
      throw new FileSystemException( "vfs.provider.s3/transfer.interrupted",
                                     src.getQualifiedName(), dst.getQualifiedName(), ie );
    } catch ( AmazonClientException e ) {
      throw new FileSystemException( "vfs.provider.s3/transfer.error",
                                     src.getQualifiedName(), dst.getQualifiedName(), e );

View on GitHub (pinned to f3058517a1)