pentaho/pentaho-kettle · error · FileSystemException
vfs.provider/copy-file.error
vfs.provider/copy-file.error
Error message
vfs.provider/copy-file.error
What it means
calculateDestination() builds the destination S3 key for a copy (bucket + relative path) and resolves the resulting S3CommonFileObject. Any exception in that resolution (invalid bucket name, malformed key, filesystem resolve failure) is wrapped in FileSystemException('vfs.provider/copy-file.error', srcFile, this, cause).
Solutions
- Verify the destination bucket exists and is writable by the configured credentials.
- Inspect the wrapped cause for the exact resolveFile() failure.
- Normalize relative paths (strip leading separators, empty segments) before building dstKey.
- Sanitize/encode special characters in file names before constructing the S3 key.
- Test the destination URI resolution independently before the bulk copy.
Example fix
// before
return (S3CommonFileObject) fileSystem.resolveFile( getName().getRoot() + DELIMITER + bucketName + DELIMITER + dstKey );
// after
String cleanKey = dstKey.replaceAll( "/+", "/" );
if ( !bucketExists( bucketName ) ) {
throw new FileSystemException( "Destination bucket missing: " + bucketName );
}
return (S3CommonFileObject) fileSystem.resolveFile( getName().getRoot() + DELIMITER + bucketName + DELIMITER + cleanKey ); Defensive patterns
Strategy: validation
Validate before calling
// before copying, validate destination key construction
if ( bucketName == null || bucketName.isEmpty() )
throw new IllegalArgumentException( "destination bucket missing" );
String cleanKey = relativePath.replaceAll( "/+", "/" );
try {
fileSystem.resolveFile( root + "/" + bucketName + "/" + cleanKey );
} catch ( FileSystemException e ) {
throw new IllegalStateException( "destination unresolvable: " + cleanKey, e );
} Try / catch
try {
dst.copyFrom( src, Selectors.SELECT_ALL );
} catch ( FileSystemException e ) {
// cause from calculateDestination() → resolveFile failure
logger.error( "copy failed resolving destination", e.getCause() );
throw e;
} Prevention
- Sanitize file names (no control characters, encoded specials) before key construction
- Ensure destination bucket exists and is writable in the target account
- Normalize relative paths to prevent double slashes or empty segments
- Validate bucket names against S3 naming rules (3-63 chars, lowercase)
When it happens
Trigger: copyFrom() walking a file tree when resolving the computed destination path fails: destination bucket does not exist, resolved key contains illegal characters, or fileSystem.resolveFile() throws for the constructed VFS URI.
Common situations: Copy into a destination bucket that does not exist or the account cannot access, source/destination path construction producing double slashes or empty key segments, special characters in filenames not URL-encodable.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- vfs.provider/copy-missing-file.error
- vfs.provider.s3/transfer.error
- vfs.provider.s3/transfer.interrupted
- vfs.provider.s3/transfer.null-argument
- Error retrieving fastload application string
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/dcdec8403759e692.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/s3-vfs/core/src/main/java/org/pentaho/s3common/S3CommonFileObject.java:438
// Destination is a folder - calculate the relative path to preserve structure
try {
String relativePath = srcBase.getName().getRelativeName( srcFile.getName() );
if ( relativePath == null || relativePath.isEmpty() ) {
relativePath = srcFile.getName().getBaseName();
}
// Build the destination key: current key + relative path
String dstKey = this.key;
if ( !dstKey.isEmpty() && !dstKey.endsWith( DELIMITER ) ) {
dstKey += DELIMITER;
}
dstKey += relativePath;
// Create a new S3CommonFileObject with the calculated key
return (S3CommonFileObject) fileSystem.resolveFile( getName().getRoot() + DELIMITER + bucketName + DELIMITER + dstKey );
} catch ( Exception e ) {
throw new FileSystemException( "vfs.provider/copy-file.error", srcFile, this, e );
}
}
/**
* Copies a single file (folders are not supported as both src and dst) from the specified source
* to the specified destination S3CommonFileObject.
* Uses S3 server-side copy if both source and destination are S3CommonFileObject.
* Falls back to S3 upload if server-side copy fails or if the source is not an S3CommonFileObject.
*
* @param src The source FileObject to copy from
* @param dst The destination S3CommonFileObject to copy to
* @throws FileSystemException If an error occurs during the copy operation.
*/
private void copySingleFileFrom( final FileObject src, final S3CommonFileObject dst ) throws FileSystemException {
S3CommonFileObject s3Src = extractDelegateS3FileObject( src );
FileSystemException copyException = null;
if ( s3Src != null ) {
// S3 to S3 copyView on GitHub (pinned to f3058517a1)