microsoft/garnet · error · ACLUnknownOperationException

{op}

Error message

{op}

What it means

Thrown by ACLParser.ApplyACLOpToUser when an operation token matches none of the recognized forms (ON/OFF/NOPASS/RESET/RESETPASS, >/</#/!, +/-@category, +/-command, ~*/ALLKEYS, RESETKEYS). Any other token is reported verbatim via ACLUnknownOperationException. This is the catch-all for completely unrecognized ACL operations.

Source

Thrown at libs/server/ACL/ACLParser.cs:270

                else
                {
                    throw new AclCommandDoesNotExistException(commandName);
                }
            }
            else if (op.Equals("~*", StringComparison.Ordinal) || op.Equals("ALLKEYS", StringComparison.OrdinalIgnoreCase))
            {
                // NOTE: No-op, because only wildcard key patterns are currently supported. If per-key key
                // patterns are ever added, the GET scatter-gather fast path (NetworkGET_SG) must re-check
                // ACL per key: it serves GETs past the first without returning through the per-command ACL
                // check in ProcessMessages, which is only safe while key access is all-or-nothing.
            }
            else if (op.Equals("RESETKEYS", StringComparison.OrdinalIgnoreCase))
            {
                // NOTE: No-op, because only wildcard key patterns are currently supported
            }
            else
            {
                throw new ACLUnknownOperationException(op);
            }

            // There's some fixup that has to be done when parsing a command
            static bool TryParseCommandForAcl(string commandName, out RespCommand command)
            {
                int subCommandSepIx = commandName.IndexOf('|');
                bool isSubCommand = subCommandSepIx != -1;

                string effectiveName = isSubCommand ? commandName[..subCommandSepIx] + "_" + commandName[(subCommandSepIx + 1)..] : commandName;

                if (!Enum.TryParse(effectiveName, ignoreCase: true, out command) || !IsValidParse(command, effectiveName))
                {
                    // Try replacing dots with empty strings for commands like RI.CREATE -> RICREATE
                    string dotlessName = effectiveName.Replace(".", "");
                    if (dotlessName != effectiveName && Enum.TryParse(dotlessName, ignoreCase: true, out command) && IsValidParse(command, dotlessName))
                    {
                        // Successfully parsed after removing dots — fall through to validation below
                    }

View on GitHub (pinned to 951b0fc683)

Solutions

  1. Check the token against the supported operation set in ApplyACLOpToUser.
  2. Prefix passwords with '>'/'<' and hashes with '#'/!' rather than leaving them bare.
  3. Use categories (+@all / -@dangerous) instead of unsupported 'allcommands'.
  4. Remove any operation Garnet does not support rather than leaving an unrecognized token.

Example fix

// before
ACLParser.ParseACLRule("user alice on allcommands secret");

// after
ACLParser.ParseACLRule("user alice on +@all >secret");
Defensive patterns

Strategy: validation

Validate before calling

var supported = new HashSet<string>(StringComparer.OrdinalIgnoreCase){"on","off","nopass","reset","resetpass","allkeys","resetkeys"};
// plus prefixed forms >, <, #, !, +, -, +@, -@, ~*
if (!(supported.Contains(op) || ">/</#/!/+/-(+@/-@/~*)".Any(p => op.StartsWith(p))))
    throw new ArgumentException($"Unsupported ACL operation: {op}");

Type guard

static bool IsSupportedOp(string op) =>
    op.Length>0 && (op[0]=='>'||op[0]=='<'||op[0]=='#'||op[0]=='!'||op[0]=='+'||op[0]=='-'||
    op.Equals("on",StringComparison.OrdinalIgnoreCase)||op.Equals("off",StringComparison.OrdinalIgnoreCase)||
    op.Equals("allkeys",StringComparison.OrdinalIgnoreCase)||op.Equals("resetkeys",StringComparison.OrdinalIgnoreCase)||
    op.Equals("nopass",StringComparison.OrdinalIgnoreCase)||op.Equals("reset",StringComparison.OrdinalIgnoreCase)||
    op.Equals("resetpass",StringComparison.OrdinalIgnoreCase));

Try / catch

try { ACLParser.ParseACLRule(line, acl); }
catch (ACLUnknownOperationException ex) { logger.LogError("Unknown op: {Op}", ex.Message); }

Prevention

When it happens

Trigger: A typo such as 'oNn' (close to but not 'on'), a stray token like 'allcommands' (Garnet does not support that; categories are used instead), or a value without an operator prefix (e.g. a bare password 'secret' instead of '>secret').

Common situations: Copy-pasting Redis ACL syntax that Garnet does not implement (e.g. 'allchannels', 'resetchannels', '>&' no-password rules); a delimiter issue leaving a fragment as its own token; hand-editing that introduced a typo.

Related errors


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