iflytek/astron-agent · error · BusinessException

S3_UPLOAD_ERROR

S3_UPLOAD_ERROR

Error message

S3_UPLOAD_ERROR

What it means

ImageService.upload wraps all exceptions raised while storing the object (S3/MinIO putObject, stream retrieval, multipart upload) into a BusinessException with code S3_UPLOAD_ERROR. The original error (name, size, type, message) is logged but replaced in the thrown exception, so any storage-layer failure surfaces as this single code.

Solutions

  1. Check the error log 'Upload image failed' for the underlying S3 error (bucket, credentials, connectivity).
  2. Verify S3/MinIO endpoint, access key, secret key, and bucket name in configuration, and that the bucket exists.
  3. Ensure the credentials/instance policy allow s3:PutObject on the target bucket.
  4. Confirm network reachability from the toolkit service to the S3/MinIO endpoint.
  5. Include the cause in the thrown exception to avoid masking the root error.

Example fix

// before
throw new BusinessException(ResponseEnum.S3_UPLOAD_ERROR);

// after
throw new BusinessException(ResponseEnum.S3_UPLOAD_ERROR, e);
Defensive patterns

Strategy: retry

Validate before calling

// Pre-flight: bucket reachable and credentials valid
s3UtilClient.headBucket(bucket); // throws early if missing/no permission

Try / catch

try {
    String key = imageService.upload(file);
} catch (BusinessException e) {
    if ("S3_UPLOAD_ERROR".equals(e.getMessage()) || ResponseEnum.S3_UPLOAD_ERROR.getCode().equals(e.getCode())) {
        // transient storage failure: bounded retry, then surface an upload-unavailable error
        return retryWithBackoff(2);
    }
    throw e;
}

Prevention

When it happens

Trigger: putObject/multipart upload throws: S3/MinIO unreachable, bucket missing, credentials rejected, bucket policy denies PutObject, network interruption mid-stream, or input stream already consumed (file.getInputStream() reused).

Common situations: MinIO endpoint/credentials misconfigured in the environment; bucket not created or wrongly named; object key policy producing invalid keys; MinIO down or out of disk; IAM/STS policy lacking s3:PutObject.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


AI-assisted analysis of iflytek/astron-agent@5e758547a8 (2026-09-12). Data as JSON: /api/errors/23bf5cfb8120447c. Report an issue: GitHub.

Appendix: source

Thrown at console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/common/ImageService.java:66

        final long size = file.getSize();

        final String original = file.getOriginalFilename();
        final String safeName = buildSafeFileName(original, contentType);
        final String objectKey = "icon/user/" + safeName;

        try (InputStream in = file.getInputStream()) {
            if (size > 0) {
                // Known content length: prefer direct upload
                s3UtilClient.putObject(objectKey, in, size, contentType);
            } else {
                // Unknown content length: fallback to multipart upload
                s3UtilClient.putObject(objectKey, in, contentType, MULTIPART_PART_SIZE);
            }
        } catch (Exception e) {
            log.error("Upload image failed, name={}, size={}, type={}, err={}",
                    original, size, contentType, e.getMessage(), e);
            throw new BusinessException(ResponseEnum.S3_UPLOAD_ERROR);
        }
        return objectKey;
    }

    /**
     * Check whether the given Content-Type is allowed.
     * <p>
     * Fallback allows any {@code image/*} if needed.
     * </p>
     *
     * @param contentType HTTP Content-Type of the file
     * @return {@code true} if allowed; {@code false} otherwise
     */
    private static boolean isAllowedType(String contentType) {
        if (contentType == null)
            return false;
        for (String t : ALLOWED_TYPES) {
            if (t.equalsIgnoreCase(contentType))

View on GitHub (pinned to 5e758547a8)