microsoft/garnet · error · ACLException

Invalid custom command name '{customName}'

Error message

Invalid custom command name '{customName}'

What it means

Thrown by User.AddCustomCommand(customName) when the supplied name fails ACLParser.IsValidCustomCommandName validation. The validator requires the first character to be alphanumeric (A-Z a-z 0-9) and all subsequent characters to be alphanumeric or '.', '_', '-', '|'. This guard prevents callers from bypassing the parser with names that would re-parse as multiple tokens on reload (poisoning the persisted Description).

Source

Thrown at libs/server/ACL/User.cs:375

            }
            while ((prev = Interlocked.CompareExchange(ref this._enabledCommands, updated, oldPerms)) != oldPerms);
        }

        /// <summary>
        /// Adds the given custom (extension) command name to the user's per-name allow list.
        /// Custom commands aren't tracked in the RespCommand bitmap (their dynamic IDs fall outside it);
        /// they live in a separate per-name allow/deny set with deny precedence at check time.
        /// </summary>
        /// <param name="customName">Custom command name. Normalized to uppercase; matching is case-insensitive.</param>
        public void AddCustomCommand(string customName)
        {
            ArgumentNullException.ThrowIfNull(customName);

            // Reject anything ACLParser would reject so the persisted Description can't be poisoned
            // by callers bypassing the parser (e.g. "foo +@all" would re-parse as two tokens on reload).
            if (!ACLParser.IsValidCustomCommandName(customName))
            {
                throw new ACLException($"Invalid custom command name '{customName}'");
            }

            string normalized = customName.ToUpperInvariant();

            CommandPermissionSet prev = this._enabledCommands;
            string descUpdate = $"+{normalized.ToLowerInvariant()}";

            CommandPermissionSet oldPerms;
            CommandPermissionSet updated;
            do
            {
                oldPerms = prev;

                // No-op fast path: already allowed.
                if (oldPerms == CommandPermissionSet.All ||
                    (oldPerms.CustomAllowed.Contains(normalized) && !oldPerms.CustomDenied.Contains(normalized)))
                {
                    return;

View on GitHub (pinned to 951b0fc683)

Solutions

  1. Sanitize the custom command name to contain only alphanumeric, '.', '_', '-', and '|' characters with an alphanumeric first character.
  2. If the name contains a subcommand separator, use the pipe form (e.g. 'MYCMD|SUB') which is explicitly allowed.
  3. Call ACLParser.IsValidCustomCommandName(name) in a unit test or precondition before invoking AddCustomCommand.

Example fix

// before
user.AddCustomCommand("my cmd!");

// after
user.AddCustomCommand("my_cmd");
Defensive patterns

Strategy: validation

Validate before calling

// Mirror the internal validation before calling AddCustomCommand
static bool IsValidCustomName(string name)
{
    if (string.IsNullOrEmpty(name)) return false;
    if (!char.IsLetterOrDigit(name[0])) return false;
    foreach (var c in name.Skip(1))
        if (!(char.IsLetterOrDigit(c) || c == '.' || c == '_' || c == '-' || c == '|'))
            return false;
    return true;
}
if (!IsValidCustomName(customName)) throw new ArgumentException($"Invalid custom command name '{customName}'");

Type guard

static bool IsValidCustomCommandName(string name) =>
    !string.IsNullOrEmpty(name) &&
    char.IsLetterOrDigit(name[0]) &&
    name.Skip(1).All(c => char.IsLetterOrDigit(c) || c is '.' or '_' or '-' or '|');

Prevention

When it happens

Trigger: Calling user.AddCustomCommand("foo +@all") (embedded space re-parses as two tokens), AddCustomCommand("") (empty), AddCustomCommand("$cmd") (illegal first char '$'), or AddCustomCommand("cmd with space"). The name is intended to mirror built-in subcommand notation like 'CLIENT|GETNAME'.

Common situations: Registering a custom/extension command under a user with a name containing whitespace, shell metacharacters, or other characters the ACL grammar treats specially; passing a raw command string instead of the cleaned command name.

Related errors


AI-assisted analysis of microsoft/garnet@951b0fc683 (2026-08-13). Data as JSON: /api/errors/cb1e08253551f758. Report an issue: GitHub.