{"record":{"id":"4d44f1cce2081898","repo":"Devolutions/UniGetUI","slug":"null-response-for-package-packageid","errorCode":null,"errorMessage":"Null response for package {packageId}","messagePattern":"Null response for package (.+?)","errorType":"exception","errorClass":"NullResponseException","httpStatus":null,"severity":"error","filePath":"src/UniGetUI.PackageEngine.Managers.Cargo/CratesIOClient.cs","lineNumber":74,"sourceCode":"internal sealed class CargoManifestPublisher\n{\n    public string? avatar { get; init; }\n    public required string name { get; init; }\n    public string? url { get; init; }\n}\n\ninternal sealed class CratesIOClient\n{\n    public const string ApiUrl = \"https://crates.io/api/v1\";\n    internal static string? TEST_ApiUrlOverride { private get; set; }\n\n    public static Tuple<Uri, CargoManifest> GetManifest(string packageId)\n    {\n        var manifestUrl = new Uri($\"{GetApiUrl()}/crates/{packageId}\");\n        var manifest = Fetch<CargoManifest>(manifestUrl);\n        if (manifest.crate is null)\n        {\n            throw new NullResponseException($\"Null response for package {packageId}\");\n        }\n        return Tuple.Create(manifestUrl, manifest);\n    }\n\n    public static CargoManifestVersion GetManifestVersion(string packageId, string version)\n    {\n        var manifestUrl = new Uri($\"{GetApiUrl()}/crates/{packageId}/{version}\");\n        var manifest = Fetch<CargoManifestVersionWrapper>(manifestUrl);\n        if (manifest.version is null)\n        {\n            throw new NullResponseException($\"Null response for package {packageId}\");\n        }\n        return manifest.version;\n    }\n\n    private static string GetApiUrl() => TEST_ApiUrlOverride ?? ApiUrl;\n\n    internal static T Fetch<T>(Uri url)","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/Devolutions/UniGetUI/blob/9b1d7d0eab91620fc15c86b36676532095936ae3/src/UniGetUI.PackageEngine.Managers.Cargo/CratesIOClient.cs#L56-L92","documentation":"CratesIOClient.GetManifest throws NullResponseException when the /crates/{id} JSON deserializes successfully but the 'crate' object is null. This indicates crates.io returned a well-formed but semantically empty payload (e.g. the crate was yanked/deleted, or an unexpected schema).","triggerScenarios":"Fetching Cargo package details for an id whose crates.io manifest has no 'crate' field, or a 200 response with an error-shaped body.","commonSituations":"Looking up a crate that was renamed/yanked; transient crates.io anomaly; packageId casing/typo that resolves to an empty manifest.","solutions":["Verify the crate exists at https://crates.io/crates/{packageId} before fetching.","Catch NullResponseException in the Cargo details helper and return a degraded details object.","Retry once on transient empty responses; if it persists, surface 'details unavailable'."],"exampleFix":"// before\nvar (url, manifest) = CratesIOClient.GetManifest(packageId);\n// after\ntry { (url, manifest) = CratesIOClient.GetManifest(packageId); }\ncatch (NullResponseException) { return details with { Name = package.Id }; }","handlingStrategy":"try-catch","validationCode":"// Validate crate exists before fetching the manifest.\n// (No cheap check; crates.io has no 'exists' endpoint — rely on try-catch.)","typeGuard":null,"tryCatchPattern":"try\n{\n    var (url, manifest) = CratesIOClient.GetManifest(packageId);\n}\ncatch (NullResponseException ex)\n{\n    Logger.Warn($\"No crate manifest for {packageId}: {ex.Message}\");\n    return details with { Name = package.Id, Description = \"Details unavailable\" };\n}","preventionTips":["Verify the crate id against the search results list before fetching details.","Catch NullResponseException in the Cargo details helper to degrade gracefully.","Retry once on transient empty responses from crates.io."],"tags":["cargo","crates-io","null-response","network","package-details"],"backgroundTag":null,"analyzedSha":"9b1d7d0eab91620fc15c86b36676532095936ae3","analyzedAt":"2026-08-13T12:19:18.278Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}