conductor-oss/conductor · error · NonTransientException

File not found on storage backend: {}

Error message

File not found on storage backend: {}

What it means

Thrown by FileStorageServiceImpl.confirmUpload after getOwnedFile succeeds but fileStorage.getStorageFileInfo reports the object is absent (null or exists=false). The metadata record exists but the actual bytes were never written to the backend, so the upload cannot be confirmed. Raised as NonTransientException (not retried; HTTP 4xx).

Source

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

        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
    public FileDownloadUrlResponse getDownloadUrl(String workflowId, String fileId) {
        FileModel model = getFamilyAccessibleFile(workflowId, fileId);
        if (model.getUploadStatus() != FileUploadStatus.UPLOADED) {
            throw new IllegalArgumentException(
                    "File not yet uploaded: " + fileId + ", status=" + model.getUploadStatus());

View on GitHub (pinned to cf7c3e4a8a)

Solutions

  1. Ensure the content was actually uploaded to the returned presigned URL before confirming.
  2. Re-request the upload URL (getUploadUrl) and PUT the bytes, then confirm again.
  3. Verify backend credentials/bucket match the configuration.
  4. If the backend is eventually consistent, retry confirm after a short delay only if transient.

Example fix

// before
FileUploadResponse r = fileStorageService.createFile(req);
// forgot to PUT bytes to r.getUploadUrl()
fileStorageService.confirmUpload(wfId, r.getFileId()); // throws

// after
FileUploadResponse r = fileStorageService.createFile(req);
http.put(r.getUploadUrl(), fileBytes);
fileStorageService.confirmUpload(wfId, r.getFileId());
Defensive patterns

Strategy: validation

Validate before calling

StorageFileInfo info = fileStorage.getStorageFileInfo(storagePath);
if (info == null || !info.isExists()) { /* upload bytes before confirming */ }

Try / catch

try {
    fileStorageService.confirmUpload(wfId, fileId);
} catch (NonTransientException e) {
    // object missing on backend; re-upload then confirm
}

Prevention

When it happens

Trigger: Calling confirmUpload without first uploading bytes to the presigned URL; the PUT to the upload URL failed silently; eventual-consistency delay where the backend has not yet registered the object; backend misconfiguration pointing at the wrong bucket/container.

Common situations: Client generated the file record and immediately confirmed without uploading content; presigned PUT returned an error the client ignored; clock/propagation delay on a strongly consistent backend; wrong storage credentials so bytes went elsewhere.

Related errors


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