conductor-oss/conductor · warning · ConflictException

File already uploaded: {}

Error message

File already uploaded: {}

What it means

Thrown by FileStorageServiceImpl.confirmUpload when the file's upload status is already UPLOADED. Confirming an already-completed upload is idempotent-rejected as a ConflictException (HTTP 409) to prevent double-completion or duplicate metadata updates.

Source

Thrown at core/src/main/java/org/conductoross/conductor/core/storage/FileStorageServiceImpl.java:102

    public FileUploadUrlResponse getUploadUrl(String workflowId, String fileId) {
        FileModel model = getOwnedFile(workflowId, fileId);
        String uploadUrl =
                fileStorage.generateUploadUrl(
                        model.getStoragePath(), properties.getSignedUrlExpiration());
        long expiresAt = Instant.now().plus(properties.getSignedUrlExpiration()).toEpochMilli();

        FileUploadUrlResponse response = new FileUploadUrlResponse();
        response.setFileHandleId(FileIdToFileHandleIdConverter.toFileHandleId(fileId));
        response.setUploadUrl(uploadUrl);
        response.setExpiresAt(expiresAt);
        return response;
    }

    @Override
    public FileUploadCompleteResponse confirmUpload(String workflowId, String fileId) {
        FileModel model = getOwnedFile(workflowId, fileId);
        if (model.getUploadStatus() == FileUploadStatus.UPLOADED) {
            throw new ConflictException("File already uploaded: " + fileId);
        }

        StorageFileInfo info = fileStorage.getStorageFileInfo(model.getStoragePath());
        if (info == null || !info.isExists()) {
            throw new NonTransientException("File not found on storage backend: " + fileId);
        }

        fileMetadataDAO.updateUploadComplete(
                fileId, FileUploadStatus.UPLOADED, info.getContentHash(), info.getContentSize());

        FileUploadCompleteResponse response = new FileUploadCompleteResponse();
        response.setFileHandleId(FileIdToFileHandleIdConverter.toFileHandleId(fileId));
        response.setUploadStatus(FileUploadStatus.UPLOADED);
        response.setContentHash(info.getContentHash());
        return response;
    }

    @Override

View on GitHub (pinned to cf7c3e4a8a)

Solutions

  1. Treat a 409 'already uploaded' as success in the client (idempotent completion).
  2. Track confirm state client-side to avoid redundant confirm calls.
  3. Use the returned status to short-circuit subsequent retries.

Example fix

// before
fileStorageService.confirmUpload(wfId, fileId); // throws on second call

// after - treat 409 as already-complete
try {
    fileStorageService.confirmUpload(wfId, fileId);
} catch (ConflictException e) {
    // already uploaded; nothing to do
}
Defensive patterns

Strategy: try-catch

Validate before calling

FileHandle meta = fileStorageService.getFileMetadata(wfId, fileId);
boolean alreadyDone = meta.getUploadStatus() == FileUploadStatus.UPLOADED;

Try / catch

try {
    fileStorageService.confirmUpload(wfId, fileId);
} catch (ConflictException e) {
    // already uploaded; treat as success
}

Prevention

When it happens

Trigger: Calling confirmUpload a second time for the same fileId; retrying confirmUpload after it already succeeded; client double-submitting the confirm request.

Common situations: At-least-once delivery with no idempotency guard on the client; frontend retry after a timeout where the first call actually succeeded; orchestrator replay of the confirm step.

Related errors


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