conductor-oss/conductor · error · TransientException

Error uploading to S3 - path:%s, payloadSize: %d

Error message

Error uploading to S3 - path:%s, payloadSize: %d

What it means

Thrown as TransientException (wrapping SdkException) by S3PayloadStorage.upload when s3Client.putObject fails with an SdkException. This covers network, credential, throttling, and S3 5xx errors during the actual object PUT. conductor marks it Transient so workflow engines can retry the upload.

Source

Thrown at awss3-storage/src/main/java/com/netflix/conductor/s3/storage/S3PayloadStorage.java:167

     */
    @Override
    public void upload(String path, InputStream payload, long payloadSize) {
        try {
            PutObjectRequest request =
                    PutObjectRequest.builder()
                            .bucket(bucketName)
                            .key(path)
                            .contentType(CONTENT_TYPE)
                            .contentLength(payloadSize)
                            .build();

            s3Client.putObject(request, RequestBody.fromInputStream(payload, payloadSize));
        } catch (SdkException e) {
            String msg =
                    String.format(
                            "Error uploading to S3 - path:%s, payloadSize: %d", path, payloadSize);
            LOGGER.error(msg, e);
            throw new TransientException(msg, e);
        }
    }

    /**
     * Downloads the payload stored in the s3 object.
     *
     * @param path the S3 key of the object
     * @return an input stream containing the contents of the object Caller is expected to close the
     *     input stream.
     */
    @Override
    public InputStream download(String path) {
        try {
            GetObjectRequest request =
                    GetObjectRequest.builder().bucket(bucketName).key(path).build();

            return s3Client.getObject(request);
        } catch (SdkException e) {

View on GitHub (pinned to cf7c3e4a8a)

Solutions

  1. Retry with exponential backoff — the exception type is explicitly Transient.
  2. Grant the role s3:PutObject on the bucket.
  3. Confirm region/bucket match and credentials are valid.
  4. If payloadSize is large, verify it is within S3 limits and that contentLength is accurate.

Example fix

// before
storage.upload(path, stream, size); // propagates TransientException
// after
RetryUtils.retryOn(TransientException.class, 5, Duration.ofMillis(300),
    () -> storage.upload(path, stream, size));
Defensive patterns

Strategy: retry

Validate before calling

import org.apache.commons.lang3.StringUtils;
if (StringUtils.isBlank(path)) throw new IllegalArgumentException("upload path is required");
if (payloadSize < 0) throw new IllegalArgumentException("payloadSize must be >= 0");
// Verify IAM policy grants s3:PutObject via an STS dry-run if available

Try / catch

// TransientException on upload is retriable
int maxAttempts = 5;
for (int attempt = 1; attempt <= maxAttempts; attempt++) {
    try {
        storage.upload(path, payload, payloadSize);
        return;
    } catch (TransientException e) {
        if (attempt == maxAttempts) throw e;
        Thread.sleep(Math.min(300L * attempt, 5000L));
    }
}

Prevention

When it happens

Trigger: Network failure during putObject; expired/invalid credentials; IAM denial on s3:PutObject; S3 throttling; payload too large hitting a limit; bucket in a different region than configured. Caught in upload's SdkException handler.

Common situations: Missing s3:PutObject permission; transient network; oversized payload; wrong region; STS session expired mid-upload.

Related errors


AI-assisted analysis of conductor-oss/conductor@cf7c3e4a8a (2026-08-14). Data as JSON: /api/errors/d5d4fc7e47cca94d. Report an issue: GitHub.