{"record":{"id":"83dfbad2d5d4f6b4","repo":"microsoft/aspire","slug":"integration-closure-metadata-line-line-is-invalid","errorCode":null,"errorMessage":"Integration closure metadata line '{line}' is invalid.","messagePattern":"Integration closure metadata line '(.+?)' is invalid\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Cli/Projects/PrebuiltAppHostServer.cs","lineNumber":1570,"sourceCode":"    private static async Task<List<string>> ReadManifestFileAsync(string filePath, CancellationToken cancellationToken)\n    {\n        if (!File.Exists(filePath))\n        {\n            throw new InvalidOperationException($\"Integration closure manifest file '{filePath}' was not found after build.\");\n        }\n\n        var lines = await File.ReadAllLinesAsync(filePath, cancellationToken).ConfigureAwait(false);\n        return lines.Where(static line => !string.IsNullOrWhiteSpace(line)).Select(static line => line.Trim()).ToList();\n    }\n\n    private static ClosureMetadata ParseClosureMetadata(string line)\n    {\n        ArgumentNullException.ThrowIfNull(line);\n\n        var parts = line.Split('|', 4);\n        if (parts.Length != 4)\n        {\n            throw new InvalidOperationException($\"Integration closure metadata line '{line}' is invalid.\");\n        }\n\n        return new ClosureMetadata(\n            NormalizeClosureMetadataValue(parts[0]),\n            NormalizeClosureMetadataValue(parts[1]),\n            NormalizeClosureMetadataValue(parts[2]),\n            NormalizeClosureMetadataValue(parts[3]));\n    }\n\n    private static string? NormalizeClosureMetadataValue(string value)\n    {\n        return string.IsNullOrWhiteSpace(value) ? null : value.Trim();\n    }\n\n    private static async Task<Dictionary<string, string>> ReadPackageFingerprintsAsync(string assetsFilePath, CancellationToken cancellationToken)\n    {\n        if (!File.Exists(assetsFilePath))\n        {","sourceCodeStart":1552,"sourceCodeEnd":1588,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Cli/Projects/PrebuiltAppHostServer.cs#L1552-L1588","documentation":"Each line of the closure metadata manifest must contain exactly 4 pipe-separated fields (artifact name, version, etc., parsed with Split('|', 4)). A line with fewer than 4 fields is structurally invalid — likely truncated or from an incompatible manifest format — so the parser throws InvalidOperationException quoting the offending line. Values are additionally normalized after the shape check.","triggerScenarios":"Parsing a metadata manifest line that contains fewer than 4 '|'-delimited segments, e.g. a blank-ish line that escaped the empty-line filter, a manually edited line, or a line written by an older/newer format with 3 fields.","commonSituations":"Hand-editing the metadata file and dropping a field; a package name or path containing '|'-related corruption; version skew where the manifest was written by a different CLI version using a different field count; partial file write leaving a truncated last line.","solutions":["Inspect the quoted line in the metadata manifest and restore the missing pipe-separated fields (expected shape: field1|field2|field3|field4).","Regenerate the closure metadata by rebuilding the prebuilt AppHost instead of editing it by hand.","Align CLI/bundle versions so the writer and parser use the same metadata line format.","Escape or re-check how the writer serializes fields if package identifiers can contain '|'."],"exampleFix":"// before (invalid, 3 fields)\nNewtonsoft.Json|13.0.3|sha256-abc123\n// after (4 fields)\nNewtonsoft.Json|13.0.3|lib/net6.0/Newtonsoft.Json.dll|sha256-abc123","handlingStrategy":"validation","validationCode":"static bool IsValidMetadataLine(string line) =>\n    !string.IsNullOrWhiteSpace(line) && line.Split('|', 4).Length == 4;","typeGuard":"static bool TryParseClosureMetadata(string line, out string[] parts) { parts = line.Split('|', 4); return parts.Length == 4; }","tryCatchPattern":"try { metadata = ParseClosureMetadata(line); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"metadata line\"))\n{ logger.LogError(ex, \"Skipping corrupt metadata line — regenerate manifest\"); }","preventionTips":["Never manually edit closure metadata files; rebuild instead.","Remember the 4-field pipe format (field1|field2|field3|field4) when generating lines.","Regenerate manifests after CLI version changes rather than diffing/patching them.","Reject writers that emit partial lines (flush/verify file completeness)."],"tags":["cli","manifest","parsing","format"],"backgroundTag":"invalid-argument-format","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"}