ThreeMammals/Ocelot · error · Exception
CompleteGitHubRelease: StatusCode =
Error message
CompleteGitHubRelease: StatusCode =
What it means
This is a Cake build-script guard thrown by CompleteGitHubRelease when the PATCH call that finalizes an existing GitHub Release (setting tag_name, body/notes, draft/prerelease flags on the release object returned by the API) does not complete successfully. The release was already created earlier in the pipeline; completing it fails when the release id/url is stale or wrong, the GITHUB token lacks repo/release scope, the tag or commitish no longer exists, or the API rejects the JSON payload. The message is assembled by concatenating the HTTP status code returned by api.github.com so the build log shows exactly why the release could not be finalized, and throwing aborts the CI release step rather than silently leaving the release in draft/incomplete state.
Solutions
- Read the logged StatusCode and URL; 404 means the release ID no longer exists — verify with GET /releases.
- 401/403: fix the GitHub token/secret scope used in SetupGitHubClient.
- 422: inspect the serialized JSON body for invalid fields before PATCHing.
- Retry on transient 5xx once the create/upload steps are confirmed successful.
Defensive patterns
Strategy: retry
Validate before calling
var check = client.GetAsync($"https://api.github.com/repos/ThreeMammals/Ocelot/releases/{releaseId}").Result;
if (check.StatusCode != HttpStatusCode.OK) throw new Exception($"Release {releaseId} not found before PATCH"); Try / catch
try { CompleteGitHubRelease(release); }
catch (Exception ex) when (ex.Message.Contains("StatusCode = ")) { Error($"Release completion failed: {ex.Message}"); throw; } Prevention
- Confirm the release still exists before PATCHing
- Validate the JSON patch body serializes correctly
- Keep the token scope stable across the whole release flow
- Retry transient 5xx with backoff
When it happens
Trigger: PATCH to api.github.com/repos/ThreeMammals/Ocelot/releases/{id} fails: 401/403 bad token or permissions, 404 wrong release ID, 422 invalid JSON patch payload, 409 conflict.
Common situations: Release was deleted between create and patch; token scope changed in CI; malformed JSON body from Newtonsoft serialization; network/proxy in CI corrupting the request.
Related errors
- CreateGitHubRelease: StatusCode =
- UploadFileToGitHubRelease: StatusCode is
- Stable release should happen via CI/CD
AI-assisted analysis of ThreeMammals/Ocelot@d1f22d9304 (2026-09-12).
Data as JSON: /api/errors/cd2125dbb9e820e0.
Report an issue: GitHub.
Appendix: source
Thrown at build.cake:1070
private void CompleteGitHubRelease(dynamic release)
{
int releaseId = release.id;
string url = release.url.ToString();
string body = ReleaseNotesAsJson();
bool isPreRelease = !IsMainBranch();
var json = $"{{ \"tag_name\": \"{versioning.NuGetVersion}\", \"target_commitish\": \"{versioning.BranchName}\", \"name\": \"{versioning.NuGetVersion}\", \"body\": \"{body}\", \"draft\": false, \"prerelease\": {isPreRelease.ToString().ToLower()} }}";
var request = new System.Net.Http.HttpRequestMessage(new System.Net.Http.HttpMethod("Patch"), url); // $"https://api.github.com/repos/ThreeMammals/Ocelot/releases/{releaseId}");
request.Content = new System.Net.Http.StringContent(json, System.Text.Encoding.UTF8, "application/json");
using (var client = new System.Net.Http.HttpClient())
{
SetupGitHubClient(client);
var result = client.SendAsync(request).Result;
if (result.StatusCode != System.Net.HttpStatusCode.OK)
{
Information($"CompleteGitHubRelease: StatusCode is {result.StatusCode}. Release ID is {releaseId}. Failed to patch release with URL: {url}");
throw new Exception("CompleteGitHubRelease: StatusCode = " + result.StatusCode);
}
}
}
/// gets the resource from the specified url
private async Task<string> GetResourceAsync(string url)
{
try
{
Information("Getting resource from " + url);
using var client = new System.Net.Http.HttpClient();
client.DefaultRequestHeaders.Accept.ParseAdd("application/vnd.github.v3+json");
client.DefaultRequestHeaders.UserAgent.ParseAdd("BuildScript");
using var response = await client.GetAsync(url);
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStringAsync();
View on GitHub (pinned to d1f22d9304)