elsa-workflows/elsa-core · error · InvalidOperationException
Secret store ' ' does not support writing secrets.
Error message
Secret store '{store.Name}' does not support writing secrets. What it means
EnsureCanWrite validates that the target ISecretStore advertises the Write capability via SecretStoreCapabilities before mutating it. Read-only stores (e.g. config/deployment-backed stores) reject writes with this InvalidOperationException. It is a capability check, not an authentication failure.
Solutions
- Write the secret to a store that supports Write (register an encrypted/writable store).
- Move the secret value into the read-only store's own configuration mechanism (appsettings/env/deployment).
- Update the custom store's Descriptor.Capabilities to include Write if it actually supports it.
- Check store selection/naming so the operation targets the intended writable store.
Example fix
// before
await secretManager.CreateSecretAsync(new CreateSecretRequest { Name = "ConnectionString" }); // resolves to read-only config store
// after
await secretManager.CreateSecretAsync(new CreateSecretRequest { Name = "ConnectionString", StoreName = "ElsaEncryptedStore" }); // writable store Defensive patterns
Strategy: validation
Validate before calling
var store = storeRegistry.GetStore(storeName);
if (store is null || !store.Descriptor.Capabilities.HasFlag(SecretStoreCapabilities.Write))
throw new InvalidOperationException($"Store '{storeName}' is read-only; choose a writable store."); Type guard
bool CanWrite(ISecretStore store) => store.Descriptor.Capabilities.HasFlag(SecretStoreCapabilities.Write);
Try / catch
try { await manager.CreateSecretAsync(request, ct); }
catch (InvalidOperationException ex) when (ex.Message.Contains("does not support writing")) { logger.LogError("Target store is read-only; provision '{Name}' via deployment config instead", request.Name); throw; } Prevention
- Mark infrastructure-managed secrets as config/env values, not runtime secrets
- Verify store capabilities before wiring secret writes
- Set an explicit StoreName on write requests
When it happens
Trigger: CreateSecretAsync or RotateAsync targeting a store whose Descriptor.Capabilities lacks SecretStoreCapabilities.Write — e.g. writing to a configuration-backed read-only store or specifying a store selector that resolves to one.
Common situations: Secret name routed to a read-only environment store; app configured with only a config-backed store; capability flags misconfigured in a custom store's Descriptor; trying to rotate infra-managed secrets from application code.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- A configuration key is required.
- A managed secret writer returned the live secret reference…
- A secret named ' ' already exists.
- A secret named ' ' already exists.
- A secret named ' ' already exists.
AI-assisted analysis of elsa-workflows/elsa-core@fe9217bdfa (2026-09-13).
Data as JSON: /api/errors/1c30aeececa12292.
Report an issue: GitHub.
Appendix: source
Thrown at src/modules/Elsa.Secrets/Services/DefaultSecretManager.cs:219
private static SecretVersion GetLatestActiveVersion(Secret secret)
{
if (secret.Status != SecretStatus.Active)
throw new InvalidOperationException($"Secret '{secret.Name}' is not active.");
return secret.LatestActiveVersion ?? throw new InvalidOperationException($"Secret '{secret.Name}' has no active version.");
}
private void ValidateName(string name)
{
if (!nameValidator.IsValid(name, out var error))
throw new InvalidOperationException(error);
}
private static void EnsureCanWrite(ISecretStore store)
{
if (!store.Descriptor.Capabilities.HasFlag(SecretStoreCapabilities.Write))
throw new InvalidOperationException($"Secret store '{store.Name}' does not support writing secrets.");
}
private static IEnumerable<Secret> ApplyFilters(IEnumerable<Secret> secrets, ListSecretsRequest request)
{
var query = secrets.Where(x => x.Status != SecretStatus.Deleted);
if (!string.IsNullOrWhiteSpace(request.Search))
{
var search = request.Search.Trim();
query = query.Where(x =>
x.Name.Contains(search, StringComparison.OrdinalIgnoreCase) ||
x.DisplayName.Contains(search, StringComparison.OrdinalIgnoreCase) ||
(x.Description?.Contains(search, StringComparison.OrdinalIgnoreCase) ?? false));
}
var typeNames = GetFilterValues(request.TypeName, request.TypeNames);
if (typeNames.Count > 0)
query = query.Where(x => typeNames.Contains(x.TypeName));View on GitHub (pinned to fe9217bdfa)