microsoft/garnet · error · ACLParsingException

ACL rules need to start with the USER keyword

Error message

ACL rules need to start with the USER keyword

What it means

Thrown by ACLParser.ParseACLRule when the first token is not 'user' (case-insensitive). The Redis/Garnet ACL rule grammar requires every rule to begin with the USER keyword. Any other leading token (typo, wrong command, stray character) is rejected as ACLParsingException.

Source

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

        /// <returns>A user object representing the modified user.</returns>
        /// <exception cref="ACLParsingException">Thrown if the ACL rule cannot be parsed.</exception>
        /// <exception cref="ACLCategoryDoesNotExistException">Thrown if the ACL command category used by the operation does not exist.</exception>
        /// <exception cref="ACLUnknownOperationException">Thrown if the given operation does not exist.</exception>
        public static User ParseACLRule(string input, AccessControlList acl = null)
        {
            // Tokenize input string 
            string[] tokens = input.Trim().Split(WhitespaceChars, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);

            // Sanity check for correctness
            if (tokens.Length < 3)
            {
                throw new ACLParsingException("Malformed ACL rule");
            }

            // Expect keyword USER
            if (!tokens[0].Equals("user", StringComparison.OrdinalIgnoreCase))
            {
                throw new ACLParsingException("ACL rules need to start with the USER keyword");
            }

            // Expect username
            string username = tokens[1];

            // Retrieve/add the user with the username to the access control list, if provided
            User user;
            if (acl != null)
            {
                user = acl.GetUserHandle(username)?.User;

                if (user == null)
                {
                    user = new User(username);
                    acl.AddUserHandle(new UserHandle(user));
                }
            }
            else

View on GitHub (pinned to 951b0fc683)

Solutions

  1. Start every ACL rule line with the literal token 'user' (case-insensitive).
  2. Prefix genuine comments with '#' so Import skips them.
  3. Run a config linter that asserts tokens[0].Equals("user", OrdinalIgnoreCase).
  4. Double-check for invisible leading characters (BOM, spaces are trimmed but stray tabs mid-token are not).

Example fix

// before
ACLParser.ParseACLRule("alice on >pass");

// after
ACLParser.ParseACLRule("user alice on >pass");
Defensive patterns

Strategy: validation

Validate before calling

var tokens = input.Trim().Split();
if (tokens.Length == 0 || !tokens[0].Equals("user", StringComparison.OrdinalIgnoreCase))
    throw new ArgumentException("ACL rule must start with 'user'");

Type guard

static bool StartsUserKeyword(string input) =>
    input.Trim().StartsWith("user", StringComparison.OrdinalIgnoreCase);

Try / catch

try { ACLParser.ParseACLRule(line, acl); }
catch (ACLParsingException ex) { /* report file:line */ }

Prevention

When it happens

Trigger: Passing a line whose first token is 'User-', 'users', 'usr', 'acl', or any non-'user' string. Also a line that begins with an operation like 'on' or a username directly.

Common situations: Mistyping the keyword; pasting a Redis CONFIG rewrite line into an ACL file; a line that is actually a comment but lacks the leading '#' (comments are skipped earlier in Import, but ParseACLRule itself does not skip them).

Related errors


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