{"record":{"id":"72d9b1f8f4bcdb43","repo":"microsoft/aspire","slug":"the-microsoft-foundry-model-catalog-response-included","errorCode":null,"errorMessage":"The Microsoft Foundry model catalog response included partial failure data in {string.Join(\", \", partialFailureFields)}. Refusing to overwrite the generated model descriptors with a partial catalog. Response: {GetResponseSnippet(content)}","messagePattern":"The Microsoft Foundry model catalog response included partial failure data in (.+?)\\. Refusing to overwrite the generated model descriptors with a partial catalog\\. Response: (.+?)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.Foundry/tools/GenModel.cs","lineNumber":938,"sourceCode":"                // after the catalog API throttles us: the observed sequence is HTTP 429 -> 200 with\n                // populated error/skip fields, i.e. a transient symptom of load/rate-limiting rather\n                // than a stable catalog state. Retry it within the same budget as 429/5xx instead of\n                // hard-aborting, so a single throttled page doesn't fail the whole run. Only once the\n                // retry budget is exhausted do we refuse, preserving the \"never overwrite the generated\n                // descriptors with a partial catalog\" guarantee. See\n                // https://github.com/microsoft/aspire/issues/18285.\n                var partialFailureFields = TryGetPartialFailureFields(content);\n                if (partialFailureFields is { Count: > 0 })\n                {\n                    if (attempt < MaxRequestAttempts)\n                    {\n                        var partialDelay = GetRetryDelay(response, content, attempt);\n                        Console.WriteLine($\"Microsoft Foundry model catalog request returned a partial catalog (populated {string.Join(\", \", partialFailureFields)}). Retrying in {partialDelay.TotalSeconds:N0}s (attempt {attempt + 1}/{MaxRequestAttempts}).\");\n                        await Task.Delay(partialDelay).ConfigureAwait(false);\n                        continue;\n                    }\n\n                    throw new InvalidOperationException($\"The Microsoft Foundry model catalog response included partial failure data in {string.Join(\", \", partialFailureFields)}. Refusing to overwrite the generated model descriptors with a partial catalog. Response: {GetResponseSnippet(content)}\");\n                }\n\n                return content;\n            }\n\n            if (IsTransientStatusCode(response.StatusCode) && attempt < MaxRequestAttempts)\n            {\n                var delay = GetRetryDelay(response, content, attempt);\n                Console.WriteLine($\"Microsoft Foundry model catalog request failed with HTTP {(int)response.StatusCode} ({response.StatusCode}). Retrying in {delay.TotalSeconds:N0}s (attempt {attempt + 1}/{MaxRequestAttempts}).\");\n                await Task.Delay(delay).ConfigureAwait(false);\n                continue;\n            }\n\n            throw new HttpRequestException($\"Microsoft Foundry model catalog request failed with HTTP {(int)response.StatusCode} ({response.StatusCode}). Response: {GetResponseSnippet(content)}\", inner: null, response.StatusCode);\n        }\n\n        throw new InvalidOperationException(\"The Microsoft Foundry model catalog request loop completed without returning or throwing.\");\n    }","sourceCodeStart":920,"sourceCodeEnd":956,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.Foundry/tools/GenModel.cs#L920-L956","documentation":"GetModelsAsync detects 'partial failure' fields in the Foundry catalog response (fields indicating some catalog data failed to load). After exhausting retries it throws, refusing to let a partially populated catalog overwrite the generated model descriptors. This keeps generated code complete and consistent.","triggerScenarios":"The catalog HTTP response contains partial-failure indicators (per GetPartialFailureFields) on every attempt up to MaxRequestAttempts, so the retry loop falls through to the final throw in GetModelsAsync.","commonSituations":"Foundry backend incident where the index is served with partial data; regional degradation; aggressive polling during an ongoing service migration; responses consistently flagged partial due to a new/renamed field tripping GetPartialFailureFields after an API update.","solutions":["Wait and re-run later — partial catalog data on the service side usually resolves on its own.","Read the listed partial-failure fields and response snippet; if the fields are false positives after an API change, update GetPartialFailureFields.","Check the Foundry service status/region health for ongoing incidents.","Retry from a different region/endpoint if the specific index is degraded."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try\n{\n    await RunGenModelAsync();\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"partial failure data\"))\n{\n    // upstream partial catalog: schedule a retry; never overwrite generated files\n}","preventionTips":["Run codegen outside of known Foundry incident windows","Check Foundry health endpoints before regenerating","Keep GetPartialFailureFields aligned with the live API schema","Schedule regeneration with automatic delayed retry"],"tags":["http","partial-data","azure-foundry","retry-exhausted"],"backgroundTag":"upstream-api-error","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T09:17:21.228Z"}