{"record":{"id":"e277de077ff31580","repo":"elsa-workflows/elsa-core","slug":"a-value-is-required-for-encrypted-secrets","errorCode":null,"errorMessage":"A value is required for encrypted secrets.","messagePattern":"A value is required for encrypted secrets\\.","errorType":"validation","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/modules/Elsa.Secrets/Stores/EncryptedSecretStore.cs","lineNumber":19,"sourceCode":"namespace Elsa.Secrets.Stores;\n\npublic class EncryptedSecretStore(ISecretValueProtector protector) : ISecretStore\n{\n    private const string ProtectedValueKey = \"protectedValue\";\n\n    public string Name => SecretStoreNames.Encrypted;\n\n    public SecretStoreDescriptor Descriptor { get; } = new(\n        SecretStoreNames.Encrypted,\n        \"Elsa Encrypted Store\",\n        \"Stores values in Elsa-managed encrypted payloads.\",\n        SecretStoreCapabilities.Read | SecretStoreCapabilities.Write | SecretStoreCapabilities.Delete | SecretStoreCapabilities.Test | SecretStoreCapabilities.Versioned,\n        false);\n\n    public Task<SecretPayload> WriteAsync(Secret secret, SecretVersion version, SecretPayload payload, CancellationToken cancellationToken = default)\n    {\n        if (payload.Value == null)\n            throw new InvalidOperationException(\"A value is required for encrypted secrets.\");\n\n        var protectedPayload = new SecretPayload();\n        protectedPayload.Metadata[ProtectedValueKey] = protector.Protect(payload.Value);\n\n        foreach (var item in payload.Metadata.Where(x => !string.Equals(x.Key, ProtectedValueKey, StringComparison.OrdinalIgnoreCase)))\n            protectedPayload.Metadata[item.Key] = item.Value;\n\n        return Task.FromResult(protectedPayload);\n    }\n\n    public Task<SecretPayload?> ReadAsync(Secret secret, SecretVersion version, CancellationToken cancellationToken = default)\n    {\n        if (!version.Payload.Metadata.TryGetValue(ProtectedValueKey, out var protectedValue))\n            return Task.FromResult<SecretPayload?>(null);\n\n        return Task.FromResult<SecretPayload?>(SecretPayload.FromValue(protector.Unprotect(protectedValue)));\n    }\n","sourceCodeStart":1,"sourceCodeEnd":37,"githubUrl":"https://github.com/elsa-workflows/elsa-core/blob/fe9217bdfa0e27f0e09e45006eb6898f616e513d/src/modules/Elsa.Secrets/Stores/EncryptedSecretStore.cs#L1-L37","documentation":"EncryptedSecretStore protects the secret value with ASP.NET DataProtection before persisting it, so a payload with a null Value cannot be encrypted. WriteAsync throws an InvalidOperationException when payload.Value is null. Only the value is protected; metadata is copied alongside the protected blob.","triggerScenarios":"Calling WriteAsync on EncryptedSecretStore with a SecretPayload whose Value property is null — e.g., a metadata-only update written through the encrypted store.","commonSituations":"Update flows that only change metadata and leave Value null; deserialization bugs producing a null value; clients written against ConfigurationSecretStore semantics (where Value may be optional) reused against the encrypted store.","solutions":["Ensure payload.Value is populated before writing to the encrypted store.","For metadata-only updates, read the existing payload, retain/copy its protected value metadata, or re-supply the value.","Validate in your service layer that Value is non-null when targeting encrypted stores."],"exampleFix":"// before\nvar payload = new SecretPayload();\npayload.Metadata[\"Environment\"] = \"Production\";\nawait encryptedStore.WriteAsync(secret, version, payload, ct);\n// after\nvar payload = new SecretPayload { Value = \"s3cr3t\" };\npayload.Metadata[\"Environment\"] = \"Production\";\nawait encryptedStore.WriteAsync(secret, version, payload, ct);","handlingStrategy":"validation","validationCode":"if (payload.Value is null)\n    throw new ArgumentException(\"Encrypted secret writes require a non-null Value.\");","typeGuard":"bool IsWritable(SecretPayload p) => p.Value is not null;","tryCatchPattern":"try\n{\n    await encryptedStore.WriteAsync(secret, version, payload, ct);\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"value is required\"))\n{\n    logger.LogError(\"Cannot write secret {SecretId}: value missing.\", secret.Id);\n}","preventionTips":["Never create SecretPayload instances without a value when targeting the encrypted store.","For metadata-only updates, load the current payload and preserve its protected value.","Validate payloads in your abstraction layer before calling the store."],"tags":["secrets","encryption","validation"],"backgroundTag":"missing-required-argument","analyzedSha":"fe9217bdfa0e27f0e09e45006eb6898f616e513d","analyzedAt":"2026-09-13T20:32:34.702Z","contentChangedAt":"2026-09-13T20:32:34.702Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}