{"record":{"id":"9d43ad5f36a9138d","repo":"microsoft/aspire","slug":"integration-closure-manifest-is-inconsistent-sources","errorCode":null,"errorMessage":"Integration closure manifest is inconsistent. Sources: {sourcePaths.Count}, metadata: {metadataLines.Count}, targets: {targetPaths.Count}.","messagePattern":"Integration closure manifest is inconsistent\\. Sources: (.+?), metadata: (.+?), targets: (.+?)\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Cli/Projects/PrebuiltAppHostServer.cs","lineNumber":827,"sourceCode":"            _logger.LogError(\"Integration project build failed. Output:\\n{BuildOutput}\", outputLines);\n            throw new AppHostServerPrepareFailedException(GetIntegrationBuildFailureMessage(buildOutput), buildOutput);\n        }\n\n        if (restoreFingerprint is not null && !skipRestore)\n        {\n            await WriteRestoreStampAsync(restoreDir, restoreFingerprint, _logger, cancellationToken).ConfigureAwait(false);\n        }\n\n        var closureSourcesPath = Path.Combine(restoreDir, ClosureSourcesFileName);\n        var closureMetadataPath = Path.Combine(restoreDir, ClosureMetadataFileName);\n        var closureTargetsPath = Path.Combine(restoreDir, ClosureTargetsFileName);\n\n        var sourcePaths = await ReadManifestFileAsync(closureSourcesPath, cancellationToken).ConfigureAwait(false);\n        var metadataLines = await ReadManifestFileAsync(closureMetadataPath, cancellationToken).ConfigureAwait(false);\n        var targetPaths = await ReadManifestFileAsync(closureTargetsPath, cancellationToken).ConfigureAwait(false);\n        if (sourcePaths.Count != metadataLines.Count || sourcePaths.Count != targetPaths.Count)\n        {\n            throw new InvalidOperationException(\n                $\"Integration closure manifest is inconsistent. Sources: {sourcePaths.Count}, metadata: {metadataLines.Count}, targets: {targetPaths.Count}.\");\n        }\n\n        var projectRefAssemblyNames = await ReadProjectRefAssemblyNamesAsync(\n            Path.Combine(restoreDir, ProjectRefAssemblyNamesFileName),\n            cancellationToken).ConfigureAwait(false);\n        var appSettingsContent = CreateAppSettingsContent(packageRefs, projectRefAssemblyNames);\n        var packageFingerprints = await ReadPackageFingerprintsAsync(\n            Path.Combine(restoreDir, \"obj\", ProjectAssetsFileName),\n            cancellationToken).ConfigureAwait(false);\n\n        var closureEntries = new List<AppHostServerClosureSource>(sourcePaths.Count);\n        for (var i = 0; i < sourcePaths.Count; i++)\n        {\n            var metadata = ParseClosureMetadata(metadataLines[i]);\n            var packageSha512 = TryGetPackageFingerprint(packageFingerprints, metadata);\n\n            closureEntries.Add(new AppHostServerClosureSource(","sourceCodeStart":809,"sourceCodeEnd":845,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Cli/Projects/PrebuiltAppHostServer.cs#L809-L845","documentation":"PrebuiltAppHostServer reads three parallel manifest files (sources, metadata lines, targets) describing the integration closure after a bundled restore/build. All three must have the same line count because line N of each file describes the same artifact. If the counts differ, the manifest was written inconsistently and the closure cannot be reconstructed safely, so the CLI throws InvalidOperationException.","triggerScenarios":"Loading a prebuilt AppHost bundle whose closure manifest files (sources, metadata, targets) were produced with mismatched line counts — e.g. a partially written, hand-edited, or stale manifest from a different build, or a manifest where blank lines were filtered differently at write time.","commonSituations":"Copying only some manifest files from another build output; an interrupted build that wrote one manifest completely but not others; manually editing one manifest (adding/removing a path) without updating the other two; using a bundle generated by an older CLI version with a different manifest format.","solutions":["Delete the bundle/restore output directory and rebuild the prebuilt AppHost so all three manifests are regenerated together.","Regenerate the manifest with the same Aspire CLI version that consumes it; do not mix versions.","If hand-maintained, verify each file has one entry per artifact in identical order (sources[i], metadata[i], targets[i] describe the same artifact)."],"exampleFix":"// before: manifest edited, sources has 5 lines but targets has 4\n// after:\naspire publish / dotnet build # regenerate the closure so Sources: 5, metadata: 5, targets: 5","handlingStrategy":"validation","validationCode":"var src = File.ReadAllLines(closureSourcesPath).Where(l => !string.IsNullOrWhiteSpace(l)).Count();\nvar meta = File.ReadAllLines(closureMetadataPath).Where(l => !string.IsNullOrWhiteSpace(l)).Count();\nvar tgt = File.ReadAllLines(closureTargetsPath).Where(l => !string.IsNullOrWhiteSpace(l)).Count();\nif (src != meta || src != tgt) throw new InvalidOperationException($\"Closure manifests out of sync: sources={src}, metadata={meta}, targets={tgt}; rebuild the bundle.\");","typeGuard":"static bool ClosureManifestsConsistent(int sources, int metadata, int targets) => sources == metadata && sources == targets;","tryCatchPattern":"try { await server.LoadClosureAsync(ct); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"closure manifest is inconsistent\"))\n{ logger.LogWarning(ex, \"Corrupt closure manifest; regenerating bundle\"); await RegenerateBundleAsync(ct); }","preventionTips":["Never hand-edit closure manifest files; always regenerate via build.","Keep all three manifest files together when copying bundle output.","Use the same CLI version to write and read bundles.","Add a build step that asserts the three manifest line counts match before packaging."],"tags":["cli","manifest","build-artifacts","consistency"],"backgroundTag":"schema-validation-failed","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"}