conductor-oss/conductor · error · AccessForbiddenException

File has no workflowId: {}

Error message

File has no workflowId: {}

What it means

Thrown by getFamilyAccessibleFile when the file record's workflowId is null or blank. Family-based read access cannot be resolved without an owning workflow in the record, so the request is denied. Raised as AccessForbiddenException (HTTP 403). This indicates corrupted/incomplete file metadata rather than a caller mistake.

Source

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

        fileStorage.abortMultipartUpload(model.getStoragePath(), uploadId);
    }

    /** Upload state may only be mutated by the workflow that created the file record. */
    private @NonNull FileModel getOwnedFile(String workflowId, String fileId) {
        FileModel model = getFileModelOrThrow(fileId);
        if (workflowId == null
                || workflowId.isBlank()
                || !workflowId.equals(model.getWorkflowId())) {
            throw new AccessForbiddenException("Workflow does not own file: " + fileId);
        }
        return model;
    }

    /** Downloads and metadata are visible to the owning workflow's full workflow family. */
    private @NonNull FileModel getFamilyAccessibleFile(String workflowId, String fileId) {
        FileModel model = getFileModelOrThrow(fileId);
        if (model.getWorkflowId() == null || model.getWorkflowId().isBlank()) {
            throw new AccessForbiddenException("File has no workflowId: " + fileId);
        }

        Set<String> family = workflowFamilyResolver.getFamily(workflowId);
        if (!family.contains(model.getWorkflowId())) {
            throw new AccessForbiddenException("Workflow cannot access file: " + fileId);
        }
        return model;
    }

    private FileModel getFileModelOrThrow(String fileId) {
        FileModel model = fileMetadataDAO.getFileMetadata(fileId);
        if (model == null) {
            throw new NotFoundException("File not found: " + fileId);
        }
        return model;
    }
}

View on GitHub (pinned to cf7c3e4a8a)

Solutions

  1. Inspect the file metadata record directly to confirm its workflowId field.
  2. Repair the record by setting the correct workflowId, or recreate the file under a valid workflow.
  3. If systemic, audit the createFile path to ensure workflowId is always persisted (note: createFile already rejects blank workflowId, so a null here implies data corruption/migration).

Example fix

// before - record has null workflowId; any download attempt throws
fileStorageService.getDownloadUrl(wfId, fileId); // 403

// after - repair the metadata or recreate the file
fileMetadataDAO.updateWorkflowId(fileId, ownerWorkflowId);
fileStorageService.getDownloadUrl(ownerWorkflowId, fileId);
Defensive patterns

Strategy: try-catch

Try / catch

try {
    fileStorageService.getDownloadUrl(wfId, fileId);
} catch (AccessForbiddenException e) {
    // file record has no workflowId (data integrity issue); repair or recreate
}

Prevention

When it happens

Trigger: Calling getDownloadUrl, downloadContent, or getFileMetadata for a file whose stored workflowId is empty (data integrity problem). The resolver cannot compute a workflow family from a missing owner.

Common situations: A legacy/migrated file record without workflowId; a bug created a file metadata row with a null workflowId; the DAO returned a partially-populated model.

Related errors


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