{"record":{"id":"9cc2c5e0784be91f","repo":"fullstackhero/dotnet-starter-kit","slug":"cannot-change-visibility-while-file-is-in-status-status","errorCode":null,"errorMessage":"Cannot change visibility while file is in status {Status}.","messagePattern":"Cannot change visibility while file is in status (.+?)\\.","errorType":"exception","errorClass":"CustomException","httpStatus":409,"severity":"error","filePath":"src/Modules/Files/Modules.Files/Domain/FileAsset.cs","lineNumber":126,"sourceCode":"    public void Restore()\n    {\n        if (!IsDeleted) return;\n        IsDeleted = false;\n        DeletedOnUtc = null;\n        DeletedBy = null;\n        UpdatedAtUtc = DateTime.UtcNow;\n    }\n\n    /// <summary>\n    /// Flip the file's <see cref=\"Visibility\"/> after upload. Idempotent. Refuses to mutate\n    /// files that haven't finished uploading or are quarantined — those are not in a state\n    /// where the URL contract is well-defined.\n    /// </summary>\n    public void ChangeVisibility(Visibility next)\n    {\n        if (Status != FileAssetStatus.Available)\n        {\n            throw new CustomException(\n                $\"Cannot change visibility while file is in status {Status}.\",\n                errors: null,\n                HttpStatusCode.Conflict);\n        }\n        if (Visibility == next) return;\n        Visibility = next;\n        UpdatedAtUtc = DateTime.UtcNow;\n    }\n}\n","sourceCodeStart":108,"sourceCodeEnd":136,"githubUrl":"https://github.com/fullstackhero/dotnet-starter-kit/blob/3f2959e683e9f83f13e55e1678c9119f63c7e8e5/src/Modules/Files/Modules.Files/Domain/FileAsset.cs#L108-L136","documentation":"FileAsset.ChangeVisibility is only allowed while the asset is Available; in any other status (PendingUpload, Quarantined, deleted/archived per the model) it throws CustomException with 409 Conflict. The doc comment notes visibility URLs are only well-defined for available files.","triggerScenarios":"Calling the change-visibility endpoint on a file still awaiting upload completion, on a quarantined (infected) file, or on an asset whose status was otherwise advanced.","commonSituations":"User toggles public/private from a stale list while the upload is still in progress; attempting to share a quarantined file; UI not refreshing status after a scan job moved the asset.","solutions":["Only offer the visibility toggle for files with status Available in the UI.","On 409, refetch the asset and show its current status to the user.","Wait for scan completion (poll or realtime update) before allowing visibility changes.","Do not attempt visibility changes on quarantined files — that state is intentionally locked."],"exampleFix":"// before\nawait api.patch(`/files/${id}/visibility`, { visibility: 'Public' }); // 409 if quarantined\n// after\nconst asset = await api.get(`/files/${id}`);\nif (asset.status !== 'Available') { showStatus(asset.status); return; }\nawait api.patch(`/files/${id}/visibility`, { visibility: 'Public' });","handlingStrategy":"type-guard","validationCode":"const asset = await api.get(`/files/${id}`);\nif (asset.status !== 'Available') { showStatus(asset.status); return; }","typeGuard":"const canChangeVisibility = (a: FileAsset): a is FileAsset & { status: 'Available' } => a.status === 'Available';","tryCatchPattern":"try { await api.patch(`/files/${id}/visibility`, { visibility }); }\ncatch (e) { if (isConflict(e)) { await refreshAsset(id); } else { throw e; } }","preventionTips":["Render the visibility toggle only for Available files","Listen for scan/quarantine events to disable stale UI","Refetch asset state after any 409"],"tags":["files","state-machine","conflict","visibility"],"backgroundTag":"invalid-state-transition","analyzedSha":"3f2959e683e9f83f13e55e1678c9119f63c7e8e5","analyzedAt":"2026-09-15T22:20:53.684Z","contentChangedAt":"2026-09-15T22:20:53.684Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}