iflytek/astron-agent · error · BusinessException
S3_UPLOAD_ERROR
S3_UPLOAD_ERROR
Error message
S3_UPLOAD_ERROR
What it means
uploadInternal wraps any exception from the S3/object-storage put into S3_UPLOAD_ERROR. After the workflow and file are validated, the artifact bytes are written to object storage; if that call fails (network error, bad credentials, bucket missing, size/quota rejection), the service translates the low-level SDK exception into this BusinessException and logs workflowId, uid, and fileName for diagnosis.
Solutions
- Check toolkit service logs for the wrapped 'Upload workflow artifact failed' stack trace to see the root SDK exception
- Verify S3/MinIO connectivity and credentials (endpoint, access key, secret, bucket) in the service configuration
- Confirm bucket exists and the service account has put-object permission; test with a direct SDK/mc upload
- Check proxy/load-balancer body-size limits and request timeouts for large files
Example fix
// before: misconfigured endpoint -> S3_UPLOAD_ERROR s3.endpoint=http://internal-minio:9000 // host unreachable // after s3.endpoint=http://minio.minio.svc.cluster.local:9000 s3.access-key=<valid-key> s3.secret-key=<valid-secret>
Defensive patterns
Strategy: retry
Validate before calling
// Pre-flight the object store before uploading
boolean ok = storageHealthCheck.ping(); // S3 headBucket or MinIO health endpoint
if (!ok) throw new IllegalStateException("Object storage unreachable, abort upload"); Try / catch
try {
artifactApi.upload(workflowId, file);
} catch (BusinessException e) {
if ("S3_UPLOAD_ERROR".equals(e.getCode())) {
log.error("S3 upload failed; check storage config/health", e);
throw new StorageUnavailableException(e); // surface infra issue, don't blindly retry
}
throw e;
} Prevention
- Health-check MinIO/S3 in deployment scripts before rolling out clients
- Keep S3 credentials/endpoint in validated config; rotate keys before expiry
- Set proxy body-size limits and timeouts above your max artifact size
- Alert on 'Upload workflow artifact failed' log entries
When it happens
Trigger: Object store unreachable or timing out during artifact upload; wrong S3 endpoint/credentials/bucket configuration; bucket quota or permission rejection; oversized multipart body dropped by a proxy before the SDK call.
Common situations: MinIO/S3 not running or misconfigured in the deployment environment; expired access keys; DNS or security-group changes breaking the storage endpoint; nginx client_max_body_size rejecting large artifacts.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
AI-assisted analysis of iflytek/astron-agent@5e758547a8 (2026-09-12).
Data as JSON: /api/errors/2c8a3f8b8b5ffd0a.
Report an issue: GitHub.
Appendix: source
Thrown at console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/workflow/WorkflowArtifactService.java:317
workflow = lockWorkflowForArtifactQuota(workflow.getId(), flowId, normalizedUid, spaceId);
enforceWorkflowArtifactQuota(workflow.getId(), file.getSize());
String objectKey = buildObjectKey(workflow.getId(), runId, validatedArtifact.fileName());
try (InputStream input = file.getInputStream()) {
s3ClientUtil.uploadObject(
artifactProperties.getArtifactBucket(),
objectKey,
validatedArtifact.contentType(),
input,
file.getSize(),
-1);
} catch (Exception ex) {
log.error(
"Upload workflow artifact failed, workflowId={}, uid={}, fileName={}",
workflow.getId(),
normalizedUid,
validatedArtifact.fileName(),
ex);
throw new BusinessException(ResponseEnum.S3_UPLOAD_ERROR);
}
try {
WorkflowArtifact artifact = new WorkflowArtifact();
LocalDateTime now = LocalDateTime.now();
artifact.setUid(normalizedUid);
artifact.setSpaceId(workflow.getSpaceId());
artifact.setWorkflowId(workflow.getId());
artifact.setRunId(StringUtils.trimToEmpty(runId));
artifact.setNodeId(StringUtils.trimToEmpty(nodeId));
artifact.setSkillId(StringUtils.trimToEmpty(skillId));
artifact.setFileName(validatedArtifact.fileName());
artifact.setObjectKey(objectKey);
artifact.setBucketName(artifactProperties.getArtifactBucket());
artifact.setContentType(validatedArtifact.contentType());
artifact.setFileSize(file.getSize());
artifact.setSource(normalizeSource(source));
artifact.setDeleted(Boolean.FALSE);
artifact.setCreateTime(now);View on GitHub (pinned to 5e758547a8)