elsa-workflows/elsa-core · error · ArgumentException

The secret field name must contain a letter or digit.

Error message

The secret field name must contain a letter or digit.

What it means

StageAsync validates that the FieldName of a ManagedSecretBindingWriteRequest contains at least one letter or digit before staging the secret material. This guard prevents field names made entirely of symbols or whitespace from entering the managed secret store, where they would produce unusable or ambiguous secret bindings.

Solutions

  1. Ensure request.FieldName contains at least one letter or digit before calling StageAsync
  2. Fix the upstream code or UI that produced a symbol-only field name
  3. Use a descriptive field name such as 'clientSecret' or 'api-key-1'

Example fix

// before
await resolver.StageAsync(new ManagedSecretBindingWriteRequest { ConnectionId = connId, FieldName = "---" });
// after
await resolver.StageAsync(new ManagedSecretBindingWriteRequest { ConnectionId = connId, FieldName = "clientSecret" });
Defensive patterns

Strategy: validation

Validate before calling

if (string.IsNullOrWhiteSpace(request.FieldName) || !request.FieldName.Any(char.IsLetterOrDigit))
    throw new ArgumentException("FieldName must contain at least one letter or digit.", nameof(request.FieldName));

Type guard

bool IsValidFieldName(string? name) => !string.IsNullOrWhiteSpace(name) && name.Any(char.IsLetterOrDigit);

Prevention

When it happens

Trigger: Calling StageAsync with a request whose FieldName is non-empty/whitespace-free but composed entirely of non-alphanumeric characters (e.g. '---', '###', '@$%'). Only characters like '.' or '-' with no letter/digit pass ThrowIfNullOrWhiteSpace but fail this check.

Common situations: Configuration values where a field name was templated or trimmed incorrectly, scripting mistakes that emit symbol-only names, or users entering a separator-like value in a Studio secret field form.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of elsa-workflows/elsa-core@fe9217bdfa (2026-09-13). Data as JSON: /api/errors/5910a80cac6185bd. Report an issue: GitHub.

Appendix: source

Thrown at src/modules/Elsa.ExternalAuthentication.Secrets/Services/ElsaSecretBindingResolver.cs:26

/// <summary>
/// Resolves External Authentication secret references through Elsa Secrets
/// without exposing secret values or generation metadata to management models.
/// </summary>
public sealed class ElsaSecretBindingResolver(
    ISecretManager secretManager,
    IExternalAuthenticationHandleHasher handleHasher) : ISecretBindingResolver, IManagedSecretBindingWriter
{
    public const string ResolverType = "elsa-secrets";
    public string Type => ResolverType;
    string IManagedSecretBindingWriter.ResolverType => ResolverType;
    string IManagedSecretBindingWriter.DisplayName => "Elsa Secrets";

    public async ValueTask<SecretBinding> StageAsync(ManagedSecretBindingWriteRequest request, CancellationToken cancellationToken = default)
    {
        ArgumentException.ThrowIfNullOrWhiteSpace(request.ConnectionId);
        ArgumentException.ThrowIfNullOrWhiteSpace(request.FieldName);
        if (!request.FieldName.Any(char.IsLetterOrDigit))
            throw new ArgumentException("The secret field name must contain a letter or digit.", nameof(request));

        // Stage every replacement under a new reference. The caller publishes
        // that reference with the connection CAS and removes it on CAS failure,
        // so a stale request can never rotate material used by the live binding.
        var name = $"external-authentication:{Guid.NewGuid():N}";
        var secret = await secretManager.CreateAsync(new()
        {
            Name = name,
            DisplayName = $"External authentication {request.FieldName}",
            TypeName = SecretTypeNames.Text,
            StoreName = SecretStoreNames.Encrypted,
            Value = request.Value.Reveal()
        }, cancellationToken);

        return new(ResolverType, secret.Name, Ownership: SecretBindingOwnership.Managed);
    }

    public async ValueTask RemoveAsync(SecretBinding binding, CancellationToken cancellationToken = default)

View on GitHub (pinned to fe9217bdfa)