{"record":{"id":"c9643f8b0b6043ec","repo":"microsoft/aspire","slug":"aspireradius044","errorCode":"ASPIRERADIUS044","errorMessage":"Secret store '{storeName}' references a SealedSecret manifest at '{manifestPath}' that is missing or unreadable ({ex.GetType().Name}). Diagnostic: ASPIRERADIUS044.","messagePattern":"Secret store '(.+?)' references a SealedSecret manifest at '(.+?)' that is missing or unreadable \\((.+?)\\)\\. Diagnostic: ASPIRERADIUS044\\.","errorType":"validation","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.Radius/Secrets/SealedSecretManifest.cs","lineNumber":73,"sourceCode":"    /// (<c>ASPIRERADIUS063</c>).\n    /// </exception>\n    internal static ValidatedManifest ReadValidated(\n        string storeName, string manifestPath, string defaultNamespace)\n    {\n        byte[] content;\n        try\n        {\n            content = File.ReadAllBytes(manifestPath);\n        }\n        // File.ReadAllBytes surfaces an unreadable path as several exception types: IO/permission\n        // failures (IOException — includes FileNotFoundException/DirectoryNotFoundException/\n        // PathTooLongException — and UnauthorizedAccessException/NotSupportedException) as well as\n        // argument failures for an empty/whitespace/invalid-character path (ArgumentException, which\n        // covers ArgumentNullException). Normalize them all to ASPIRERADIUS044 so every \"unreadable\n        // manifest\" failure matches the XML-doc/README contract instead of leaking a raw exception.\n        catch (Exception ex) when (ex is IOException or PathTooLongException or UnauthorizedAccessException or NotSupportedException or ArgumentException)\n        {\n            throw new InvalidOperationException(\n                $\"Secret store '{storeName}' references a SealedSecret manifest at '{manifestPath}' that \" +\n                $\"is missing or unreadable ({ex.GetType().Name}). Diagnostic: ASPIRERADIUS044.\", ex);\n        }\n\n        string text;\n        try\n        {\n            text = s_utf8.GetString(content);\n        }\n        catch (DecoderFallbackException ex)\n        {\n            throw new InvalidOperationException(\n                $\"Secret store '{storeName}' references a SealedSecret manifest at '{manifestPath}' that \" +\n                \"is not valid UTF-8 YAML. Diagnostic: ASPIRERADIUS044.\", ex);\n        }\n\n        var metadata = ReadMetadataFromYaml(storeName, manifestPath, defaultNamespace, text);\n        return new ValidatedManifest(metadata, manifestPath, content);","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.Radius/Secrets/SealedSecretManifest.cs#L55-L91","documentation":"Thrown for ASPIRERADIUS044 when a secret store references a SealedSecret manifest file that cannot be read: the file is missing, or any IO/path/permission/argument error occurs while opening it. All such failures (IOException, PathTooLongException, UnauthorizedAccessException, NotSupportedException, ArgumentException incl. empty/invalid paths) are normalized to this single diagnostic so every 'unreadable manifest' failure matches the documented contract instead of leaking a raw exception.","triggerScenarios":"Calling WithSealedSecret (leading to SealedSecretManifest.ReadValidated/ReadMetadata) with a path that does not exist, a relative path resolved against an unexpected working directory, a path that is too long, a file without read permission, or an empty/whitespace/invalid-character path string.","commonSituations":"Using a relative path whose working directory differs between dev machine and CI; forgetting to copy the manifest into the build output; passing an environment-variable-derived path that is unset (empty string); moving the manifest file after wiring the store.","solutions":["Verify the file exists at the exact path passed to WithSealedSecret (use an absolute path).","If the manifest must ship with the app, mark it CopyToOutputDirectory and reference the output location.","Check file permissions and that the path contains no invalid characters or is not empty.","Ensure the inner exception (ex) reported alongside this message for the underlying cause (e.g. FileNotFoundException) is addressed."],"exampleFix":"// before\nstore.WithSealedSecret(\"sealed-secret.yaml\"); // relative; missing in CI\n\n// after\nvar manifestPath = Path.Combine(AppContext.BaseDirectory, \"sealed-secret.yaml\");\nif (!File.Exists(manifestPath)) throw new FileNotFoundException(\"SealedSecret manifest missing\", manifestPath);\nstore.WithSealedSecret(manifestPath);","handlingStrategy":"validation","validationCode":"// Check the manifest before calling WithSealedSecret.\nif (string.IsNullOrWhiteSpace(manifestPath) || !File.Exists(manifestPath))\n    throw new FileNotFoundException($\"SealedSecret manifest not found: {manifestPath}\", manifestPath);","typeGuard":null,"tryCatchPattern":"try { store = store.WithSealedSecret(manifestPath); } catch (InvalidOperationException ex) when (ex.Message.Contains(\"ASPIRERADIUS044\")) { logger.LogError(ex, \"Manifest unreadable at {Path}\", manifestPath); throw; }","preventionTips":["Use absolute paths (e.g. Path.Combine(AppContext.BaseDirectory, ...)) for manifests.","Mark manifests CopyToOutputDirectory so they exist next to the built app.","Assert file existence in a startup check or unit test before wiring stores."],"tags":["radius","secrets","sealed-secret","file-io"],"backgroundTag":"file-not-found","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}