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
- Sanitize the custom command name to contain only alphanumeric, '.', '_', '-', and '|' characters with an alphanumeric first character.
- If the name contains a subcommand separator, use the pipe form (e.g. 'MYCMD|SUB') which is explicitly allowed.
- 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
- Pre-validate custom command names with the same character rules as ACLParser.IsValidCustomCommandName.
- Allow only alphanumeric, '.', '_', '-', and '|' in names.
- Write unit tests for AddCustomCommand covering illegal-character inputs.
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.