{"record":{"id":"673d941eaf3f5630","repo":"fullstackhero/dotnet-starter-kit","slug":"not-allowed-to-change-this-file-s-visibility","errorCode":null,"errorMessage":"not allowed to change this file's visibility","messagePattern":"not allowed to change this file's visibility","errorType":"exception","errorClass":"ForbiddenException","httpStatus":403,"severity":"warning","filePath":"src/Modules/Files/Modules.Files/Features/v1/ChangeVisibility/ChangeFileVisibilityCommandHandler.cs","lineNumber":46,"sourceCode":"        {\n            throw new CustomException(\n                $\"Unknown visibility value '{cmd.Visibility}'.\",\n                errors: null,\n                System.Net.HttpStatusCode.BadRequest);\n        }\n\n        var f = await db.FileAssets\n            .FirstOrDefaultAsync(x => x.Id == cmd.FileAssetId, cancellationToken)\n            .ConfigureAwait(false)\n            ?? throw new NotFoundException(\"file not found\");\n\n        var userId = currentUser.GetUserId().ToString();\n        var policy = policies.Resolve(f.OwnerType)\n            ?? throw new ForbiddenException(\"no policy\");\n        var ctx = new FileAccessContext(f.Id, f.OwnerType, f.OwnerId, f.CreatedByUserId, (int)f.Visibility);\n        if (!await policy.CanChangeVisibilityAsync(ctx, userId, cancellationToken).ConfigureAwait(false))\n        {\n            throw new ForbiddenException(\"not allowed to change this file's visibility\");\n        }\n\n        f.ChangeVisibility(cmd.Visibility);\n        await db.SaveChangesAsync(cancellationToken).ConfigureAwait(false);\n\n        var publicUrl = f.Visibility == Visibility.Public\n            ? storage.BuildPublicUrl(f.StorageKey)\n            : null;\n        return FileAssetMapper.ToDto(f, publicUrl);\n    }\n}\n","sourceCodeStart":28,"sourceCodeEnd":58,"githubUrl":"https://github.com/fullstackhero/dotnet-starter-kit/blob/3f2959e683e9f83f13e55e1678c9119f63c7e8e5/src/Modules/Files/Modules.Files/Features/v1/ChangeVisibility/ChangeFileVisibilityCommandHandler.cs#L28-L58","documentation":"The resolved access policy's CanChangeVisibilityAsync returned false for (file, userId), so the handler throws ForbiddenException. The policy receives FileAccessContext (owner type/id, creator, current visibility) and encodes business rules such as 'only the creator or an admin may flip visibility'.","triggerScenarios":"Authenticated user calls change-visibility on a file they are not permitted to manage: not the creator, not an owner/admin for the OwnerType, or the policy's role/permission check fails for that user.","commonSituations":"User attempts to publish a teammate's file; a normal tenant user tries to make a file public in a deployment where only admins may; API client calls with a user token that lacks the file-management permission; owner-type policy was tightened and old UI still allows the action.","solutions":["Confirm the acting user actually owns/created the file or holds the admin/owner role the policy requires.","Review the OwnerType policy implementation (CanChangeVisibilityAsync) to see which condition failed and align the request with it.","If the rule is wrong, change the policy implementation — do not bypass it in the handler.","Check that ICurrentUser resolves the intended user (token/impersonation) rather than a different identity."],"exampleFix":"// before\nawait client.ChangeVisibilityAsync(fileOwnedBySomeoneElseId, Visibility.Public); // 403\n// after\nvar file = await client.GetFileAsync(id);\nif (file.CreatedByUserId == currentUserId) await client.ChangeVisibilityAsync(id, Visibility.Public);","handlingStrategy":"try-catch","validationCode":"var file = await client.GetFileAsync(id);\nif (file.CreatedByUserId != currentUserId && !userIsAdmin) throw new UnauthorizedAccessException(\"Only the creator or an admin may change visibility.\");","typeGuard":null,"tryCatchPattern":"catch (ForbiddenException e) when (e.Message.Contains(\"visibility\")) {\n    notify(\"You do not have permission to change this file's visibility.\");\n}","preventionTips":["Hide/disable visibility controls in the UI unless the user is the creator or admin.","Check policy rules before calling the API, not after.","Keep client permission state in sync with server-side policy changes.","Log 403s with file id and user id to diagnose which policy clause failed."],"tags":["authorization","forbidden","files","policy"],"backgroundTag":"permission-denied","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"}