{"record":{"id":"dd54d54db8e207e7","repo":"microsoft/aspire","slug":"secret-store-storename-references-a-manifest-at-manifestpath-dd54d5","errorCode":null,"errorMessage":"Secret store '{storeName}' references a manifest at '{manifestPath}' that has a spec.encryptedData entry '{key}' that is not a non-empty standard-base64 encoded sealed value. Seal the secret with kubeseal instead of writing the value by hand.","messagePattern":"Secret store '(.+?)' references a manifest at '(.+?)' that has a spec\\.encryptedData entry '(.+?)' that is not a non-empty standard-base64 encoded sealed value\\. Seal the secret with kubeseal instead of writing the value by hand\\.","errorType":"validation","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.Radius/Secrets/SealedSecretManifest.cs","lineNumber":296,"sourceCode":"\n        foreach (var (keyNode, valueNode) in encryptedData.Children)\n        {\n            // ValidateStructure already rejects non-scalar mapping keys, so the key is a scalar here;\n            // read it defensively for the diagnostic message only.\n            var key = (keyNode as YamlScalarNode)?.Value ?? \"<non-scalar>\";\n\n            // kubeseal writes each value with Go's base64.StdEncoding and the controller decodes it the\n            // same way, so anything that is not a standard-base64 scalar cannot be a sealed value. This\n            // does not prove the value is ciphertext (plaintext can be valid base64), but it fails\n            // closed on the shapes the CRD never produces: nested mappings/sequences, empty/whitespace\n            // values, and most implicit non-string scalars (`123`, `~`). It cannot reject a short plain\n            // scalar that happens to be valid base64 (`true`), and a minimum length is deliberately not\n            // enforced because the ciphertext length is not a documented part of the format.\n            // https://github.com/bitnami-labs/sealed-secrets/blob/main/pkg/apis/sealedsecrets/v1alpha1/sealedsecret_expansion.go\n            if (valueNode is not YamlScalarNode { Value: { Length: > 0 } value } ||\n                !IsStandardBase64(value))\n            {\n                throw CreateInvalidManifestException(\n                    storeName,\n                    manifestPath,\n                    $\"has a spec.encryptedData entry '{key}' that is not a non-empty standard-base64 encoded sealed \" +\n                    \"value. Seal the secret with kubeseal instead of writing the value by hand.\");\n            }\n        }\n    }\n\n    private static bool IsStandardBase64(string value) =>\n        // Base64.IsValid validates without allocating a decode buffer (the ciphertext can be large).\n        // It ignores whitespace, so require a non-zero decoded length to reject a whitespace-only value.\n        Base64.IsValid(value, out var decodedLength) && decodedLength > 0;\n\n    private static bool ContainsPlaintextTemplateData(YamlMappingNode template, string field) =>\n        TryGetNode(template, field, out var value) && HasContent(value);\n\n    // The annotation key `kubectl apply` uses to stash the last-applied object JSON.\n    private const string LastAppliedConfigurationAnnotation = \"kubectl.kubernetes.io/last-applied-configuration\";","sourceCodeStart":278,"sourceCodeEnd":314,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.Radius/Secrets/SealedSecretManifest.cs#L278-L314","documentation":"When reading a Radius sealed-secret manifest, each spec.encryptedData entry must be a non-empty string that is valid standard (padded) base64, because it represents ciphertext produced by kubeseal. This error is thrown when an entry is missing, empty, not a scalar, or not standard base64, indicating the value was written by hand rather than sealed.","triggerScenarios":"ReadMetadataFromRoot -> ValidateEncryptedData encounters an encryptedData value that is empty, a non-scalar YAML node (e.g. a boolean like `true`), or a string that is not standard base64 (missing padding, URL-safe characters, or arbitrary text).","commonSituations":"Developers hand-editing a SealedSecret manifest and typing a plaintext or hex value; copying ciphertext that lost base64 padding; using URL-safe base64 from non-kubeseal tooling; YAML unquoting values like `true` into booleans.","solutions":["Re-seal the secret with `kubeseal < secret.yaml > sealed.yaml` so encryptedData contains genuine kubeseal output","Check each encryptedData value decodes with Convert.FromBase64String (standard alphabet, padding required); fix truncated or whitespace-corrupted values","Quote the value in YAML so scalar types like `true` remain strings","Ensure the value is non-empty and was copied completely (no truncation at line-wrap)"],"exampleFix":"// before\nspec:\n  encryptedData:\n    password: my-plaintext-password\n// after\n# echo -n 'my-plaintext-password' | kubeseal --raw > cipher.b64\nspec:\n  encryptedData:\n    password: \"AgBj3mQ9...==\"","handlingStrategy":"validation","validationCode":"bool IsValidEncryptedDataValue(string? v) =>\n    !string.IsNullOrEmpty(v) && Convert.TryFromBase64String(v, new byte[(v.Length * 3) / 4 + 3], out _);","typeGuard":"bool IsStandardBase64String(object? v) => v is string s && !string.IsNullOrEmpty(s) && Convert.TryFromBase64String(s, new byte[s.Length], out _);","tryCatchPattern":null,"preventionTips":["Always produce encryptedData via kubeseal, never hand-write values","Quote base64 values in YAML to avoid boolean/numeric coercion","Verify values decode as standard base64 (with padding) before committing manifests"],"tags":["yaml","base64","sealed-secrets","validation"],"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"}