{"record":{"id":"d96b57a411c17d66","repo":"Devolutions/UniGetUI","slug":"null-response-for-request-to-url","errorCode":null,"errorMessage":"Null response for request to {url}","messagePattern":"Null response for request to (.+?)","errorType":"exception","errorClass":"NullResponseException","httpStatus":null,"severity":"error","filePath":"src/UniGetUI.PackageEngine.Managers.Cargo/CratesIOClient.cs","lineNumber":104,"sourceCode":"        }\n        return manifest.version;\n    }\n\n    private static string GetApiUrl() => TEST_ApiUrlOverride ?? ApiUrl;\n\n    internal static T Fetch<T>(Uri url)\n    {\n        using HttpClient client = new(CoreTools.GenericHttpClientParameters);\n        client.DefaultRequestHeaders.UserAgent.ParseAdd(CoreData.UserAgentString);\n        using var request = new HttpRequestMessage(HttpMethod.Get, url);\n        using HttpResponseMessage response = client.Send(request);\n        response.EnsureSuccessStatusCode();\n\n        string manifestStr = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();\n\n        var manifest =\n            CargoJson.Deserialize<T>(manifestStr)\n            ?? throw new NullResponseException($\"Null response for request to {url}\");\n        return manifest;\n    }\n}\n\npublic class NullResponseException(string message) : Exception(message);\n","sourceCodeStart":86,"sourceCodeEnd":110,"githubUrl":"https://github.com/Devolutions/UniGetUI/blob/9b1d7d0eab91620fc15c86b36676532095936ae3/src/UniGetUI.PackageEngine.Managers.Cargo/CratesIOClient.cs#L86-L110","documentation":"CratesIOClient.Fetch<T> throws NullResponseException when CargoJson.Deserialize<T> returns null. The HTTP status was already verified success (EnsureSuccessStatusCode), so a null here means the body parsed to JSON but could not map to T, or the body was 'null'.","triggerScenarios":"Any crates.io GET where the response is HTTP 200 but the JSON is 'null' or does not match the expected record shape T (missing required init members throw earlier, so null specifically means the deserializer returned null).","commonSituations":"Schema mismatch after a crates.io API change; an empty 200 body; a record type T with a custom converter that returns null.","solutions":["Log the raw body for the failing URL when this fires to confirm the actual payload shape.","Ensure CargoJson JsonSerializerContext includes T and that required members are present in the payload.","Treat NullResponseException as a non-retryable data error for that id and degrade gracefully."],"exampleFix":"// before\nvar data = CratesIOClient.Fetch<T>(url);\n// after\nT data;\ntry { data = CratesIOClient.Fetch<T>(url); }\ncatch (NullResponseException ex) { Logger.Warn(ex.Message); return default; }","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try\n{\n    return CratesIOClient.Fetch<T>(url);\n}\ncatch (NullResponseException ex)\n{\n    Logger.Warn($\"Crates.io returned null for {url}: {ex.Message}\");\n    return default;\n}","preventionTips":["Keep CargoJson JsonSerializerContext registered for all T types fetched.","Log raw bodies on null-response to catch schema drift early.","Treat persistent null responses as a data problem, not a transient retry."],"tags":["cargo","crates-io","json-deserialize","null-response","network"],"backgroundTag":null,"analyzedSha":"9b1d7d0eab91620fc15c86b36676532095936ae3","analyzedAt":"2026-08-13T12:19:18.278Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}