{"record":{"id":"24a6a001bf8d34d0","repo":"pentaho/pentaho-kettle","slug":"vfs-provider-s3-transfer-null-argument","errorCode":"vfs.provider.s3/transfer.null-argument","errorMessage":"vfs.provider.s3/transfer.null-argument","messagePattern":"vfs\\.provider\\.s3/transfer\\.null-argument","errorType":"error_code","errorClass":"FileSystemException","httpStatus":null,"severity":"error","filePath":"plugins/s3-vfs/core/src/main/java/org/pentaho/s3common/S3TransferManager.java","lineNumber":57,"sourceCode":"  }\n\n  public TransferManager getTransferManager() {\n    return transferManager;\n  }\n\n  /**\n   * Perform S3->S3 multipart copy with a custom thread pool size.\n   *\n   * @param src           Source S3FileObject\n   * @param dst           Destination S3FileObject\n   * @param logger        Logger for logging\n   * @throws FileSystemException if copy fails\n   */\n  public void copy( S3CommonFileObject src, S3CommonFileObject dst ) throws FileSystemException {\n    if ( src == null || dst == null\n      || src.bucketName == null || src.key == null\n      || dst.bucketName == null || dst.key == null ) {\n      throw new FileSystemException( \"vfs.provider.s3/transfer.null-argument\",\n        src != null ? src.getQualifiedName() : \"null\",\n        dst != null ? dst.getQualifiedName() : \"null\" );\n    }\n    try {\n      Copy copy = getTransferManager().copy(\n        src.bucketName, src.key,\n        dst.bucketName, dst.key\n      );\n      copy.waitForCompletion();\n      logger.info( \"S3->S3 server-side copy succeeded: {} -> {}\",\n                   src.getQualifiedName(), dst.getQualifiedName() );\n    } catch ( InterruptedException ie ) {\n      Thread.currentThread().interrupt();\n      throw new FileSystemException( \"vfs.provider.s3/transfer.interrupted\",\n                                     src.getQualifiedName(), dst.getQualifiedName(), ie );\n    } catch ( AmazonClientException e ) {\n      throw new FileSystemException( \"vfs.provider.s3/transfer.error\",\n                                     src.getQualifiedName(), dst.getQualifiedName(), e );","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/plugins/s3-vfs/core/src/main/java/org/pentaho/s3common/S3TransferManager.java#L39-L75","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Null-check both FileObjects and confirm they are resolved S3 objects before calling copy","Ensure bucketName and key are populated by resolving via the S3 VFS provider (s3://bucket/key)","Log the two qualified names in the message to identify which argument is bad","Fix the upstream code that produced an unresolved/null file object"],"exampleFix":"// before\ntransferManager.copy( src, dst );\n// after\nif ( src != null && dst != null && src.bucketName != null && src.key != null\n  && dst.bucketName != null && dst.key != null ) {\n  transferManager.copy( src, dst );\n} else {\n  throw new IllegalArgumentException( \"src/dst must be resolved S3 file objects\" );\n}","handlingStrategy":"type-guard","validationCode":"if ( src == null || dst == null\n  || src.bucketName == null || src.key == null\n  || dst.bucketName == null || dst.key == null ) {\n  throw new IllegalArgumentException( \"both src and dst must be resolved s3://bucket/key objects\" );\n}","typeGuard":"boolean isResolvedS3File( FileObject f ) {\n  return f instanceof S3CommonFileObject\n    && ((S3CommonFileObject) f).bucketName != null\n    && ((S3CommonFileObject) f).key != null;\n}","tryCatchPattern":"try {\n  transferManager.copy( src, dst );\n} catch ( FileSystemException e ) {\n  if ( \"vfs.provider.s3/transfer.null-argument\".equals( e.getMessage() ) ) {\n    // inspect the two names in the message to see which side was null\n  }\n  throw e;\n}","preventionTips":["Always resolve FileObjects through the S3 provider before transfer calls","Check for silently-failed resolutions earlier in the pipeline","Assert non-null bucket/key at construction/wiring time","Unit-test transfer wiring with unresolved-file scenarios"],"tags":["s3","vfs","null-check","copy"],"backgroundTag":"null-argument","analyzedSha":"f3058517a153da500bf4551f46d79b91bf8ec552","analyzedAt":"2026-09-13T14:04:16.340Z","contentChangedAt":"2026-09-13T14:04:16.340Z","schemaVersion":2},"datasetVersion":"2026-09-20T23:17:15.980Z"}