pentaho/pentaho-kettle · error · FileSystemException
vfs.provider/create-file.error
vfs.provider/create-file.error
Error message
vfs.provider/create-file.error
What it means
S3CommonFileObject.createFile() (PDI-19598 override of the VFS default) refuses to create a file if the target exists in S3 but is not a regular file (e.g. it is a folder/prefix). It throws FileSystemException('vfs.provider/create-file.error', name) without a cause — the invariant 'existing object must be a file' was violated.
Solutions
- Choose a different target key that does not collide with an existing folder prefix.
- Delete the folder placeholder object in S3 before creating the file.
- Check exists() && isFile() before calling createFile() and handle the collision explicitly.
- Use folder delimiter conventions consistently in your pipeline paths.
Example fix
// before
fileObject.createFile();
// after
if ( fileObject.exists() && !fileObject.isFile() ) {
throw new IOException( "Target exists as a folder in S3: " + fileObject.getName() );
}
fileObject.createFile(); Defensive patterns
Strategy: validation
Validate before calling
if ( fileObject.exists() ) {
if ( !fileObject.isFile() ) {
throw new IllegalStateException( "S3 target is a folder, not a file: " + fileObject.getName() );
}
}
// safe to createFile() now Try / catch
try {
fileObject.createFile();
} catch ( FileSystemException e ) {
if ( fileObject.exists() && fileObject.getType() != FileType.FILE ) {
// collision with an S3 folder placeholder — pick a new key
}
throw e;
} Prevention
- Never name files the same as existing folder prefixes in a bucket
- Enforce a single convention for keys (either with or without trailing slashes)
- Enumerate prefixes before bulk writes to detect collisions
- Use separate bucket/prefixes for folder-like vs file-like data
When it happens
Trigger: Calling createFile() (e.g. via fileObject.createFile() or resolving then writing) on an S3 key that already exists as a folder/directory object (zero-byte key ending with '/').
Common situations: Overwriting an S3 'folder' with a file of the same name, VFS path resolving to a prefix created by the S3 console, or conflicting naming conventions between prefix-style keys and files.
Understand the failure class
Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.
Related errors
- Exception getting the list of buckets
- FileSystemException wrapping KettleFileException
- FileSystemException wrapping SdkClientException
- vfs.provider/copy-file.error
- vfs.provider/copy-missing-file.error
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/36d88620621ccd69.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/s3-vfs/core/src/main/java/org/pentaho/s3common/S3CommonFileObject.java:94
return new S3CommonFileInputStream( streamS3Object.getObjectContent(), streamS3Object );
}
@Override
public Path getPath() {
// default impl will only work for schemes registered with nio
String namePath = getName().getPath();
String[] pathElements = StringUtils.split( namePath, DELIMITER );
return Path.of( "", pathElements );
}
@Override public void createFile() throws FileSystemException {
//PDI-19598: Copied from super.createFile() but it was a way to force the file creation on S3
synchronized ( fileSystem ) {
try {
// VFS-210: We do not want to trunc any existing file, checking for its existence is
// still required
if ( exists() && !isFile() ) {
throw new FileSystemException( "vfs.provider/create-file.error", super.getName() );
}
if ( !exists() ) {
try ( OutputStream outputStream = getOutputStream() ) {
//Force to write an empty array to force file creation on S3 bucket
outputStream.write( new byte[] {} );
}
endOutput();
}
} catch ( final RuntimeException re ) {
throw re;
} catch ( final Exception e ) {
throw new FileSystemException( "vfs.provider/create-file.error", super.getName(), e );
}
}
}
@OverrideView on GitHub (pinned to f3058517a1)