From d2a0c263dd4a6b8bbdaa97325af99bed93cb43a9 Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Fri, 21 Aug 2026 22:08:05 +0100 Subject: [PATCH] acl post: reject BlogPostId <= 0 with 400, no 500 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 2026-08-21 prod 500 on POST /api/v1/blogacl was caused by the PostIt client sending { circleId } only — the server deserialised into CircleAuthorizationToBlogPost with BlogPostId = default(long) = 0, and EF Core refused the INSERT with InvalidOperationException. The PostIt-side fix lives in b82b6722 (enrich the payload with blogPostId). This commit is the server-side guard: validate BlogPostId > 0 in the controller and return 400 BadRequest instead of letting the request reach SaveChangesAsync. The same shape that crashed on 2026-08-21 now fails fast at the validation layer. Verified by BlogAclApiTests.PostCircleAuthorization_dosent_return_500: sentinel that asserts 'never 500' on a payload with BlogPostId = -1. Previously red (500 from EF Core), now green (400 from the new guard). --- src/Yavsc.Blogs/Controllers/BlogAclApiController.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Yavsc.Blogs/Controllers/BlogAclApiController.cs b/src/Yavsc.Blogs/Controllers/BlogAclApiController.cs index 18f6f1bf..a33d75d8 100644 --- a/src/Yavsc.Blogs/Controllers/BlogAclApiController.cs +++ b/src/Yavsc.Blogs/Controllers/BlogAclApiController.cs @@ -111,6 +111,15 @@ namespace Yavsc.Blogs.Controllers { return BadRequest(ModelState); } + // No 500: a missing or zero BlogPostId is a client + // error, not an EF Core FK violation waiting to happen. + // The 2026-08-21 prod 500 was this exact path (PostIt + // sent only circleId, server saw BlogPostId = 0 and + // SaveChangesAsync threw InvalidOperationException). + if (circleAuthorizationToBlogPost.BlogPostId <= 0) + { + return BadRequest("BlogPostId is required and must be > 0."); + } if (!await CheckOwnerAsync(circleAuthorizationToBlogPost.CircleId)) { return new ChallengeResult();