microsoft/garnet · error · GarnetException

ACL strict mode: {unresolved.Count} unresolved (user, custom

Error message

ACL strict mode: {unresolved.Count} unresolved (user, custom-command) entries in ACL rules: {entries}. Disable acl-strict-custom-commands or load the appropriate module(s).

What it means

Thrown during GarnetServer initialization when ACL strict mode (opts.AclStrictCustomCommands) is enabled and one or more ACL rules reference custom commands that are not registered with any loaded module. The strict mode is a fail-closed safety mechanism: it prevents operators from shipping ACL configurations with typos that would silently deny commands. The error lists the specific unresolved user-command pairs.

Source

Thrown at libs/host/GarnetServer.cs:360

                }
            }

            if (unresolved.Count == 0)
            {
                return;
            }

            foreach (var (user, name) in unresolved)
            {
                logger?.LogWarning("ACL rule references custom command '{name}' for user '{user}' which is not registered with any loaded module", name, user);
            }

            if (opts.AclStrictCustomCommands)
            {
                // Strict mode: fail closed so operators can't accidentally ship an ACL with typos
                // that would silently match no command (and therefore deny by default at dispatch).
                var entries = string.Join(", ", unresolved.Select(t => $"({t.user},{t.name})"));
                throw new GarnetException($"ACL strict mode: {unresolved.Count} unresolved (user, custom-command) entries in ACL rules: {entries}. Disable acl-strict-custom-commands or load the appropriate module(s).");
            }
        }

        private GarnetDatabase CreateDatabase(int dbId, GarnetServerOptions serverOptions, ClusterFactory clusterFactory,
            CustomCommandManager customCommandManager)
        {
            var removeOutdated = !serverOptions.EnableCluster;
            // Two-roots layout for RangeIndex files:
            //  riLogRoot — log-tied (working file + per-flush snapshots), co-located with hlog.
            //              Falls back through LogDir → CheckpointDir → cwd, mirroring Tsavorite's
            //              CheckpointBaseDirectory chain so RangeIndex works without storage tier.
            //  cprDir    — checkpoint-tied (per-token snapshots live under <token>/rangeindex/),
            //              alongside Tsavorite's cpr-checkpoints/<token>/info.dat etc.
            // Construct the manager only when the feature is enabled. When disabled, the
            // store wrapper / triggers / functions hold a null reference, and Tsavorite's
            // record-trigger gates (CallOnFlush etc.) return false → zero per-op overhead.
            RangeIndexManager rangeIndexManager = null;
            if (serverOptions.EnableRangeIndexPreview)

View on GitHub (pinned to 951b0fc683)

Solutions

  1. Load the appropriate module(s) that register the referenced custom commands before the ACL is validated.
  2. Fix typos in the ACL file — the error message lists the specific (user, command) pairs.
  3. If you intentionally want to ship ACLs with not-yet-loaded commands, set AclStrictCustomCommands=false (but note this weakens the safety check).
  4. Verify that module command registration names exactly match the names used in ACL rules.

Example fix

// before: ACL references 'MYCMD' but module not loaded
//   user alice on >password ~* +MYCMD

// after: load module first or fix command name
//   garnet-server --loadmodule ./mymodule.so
//   user alice on >password ~* +MYCMD
Defensive patterns

Strategy: validation

Validate before calling

// Before strict validation, verify all ACL-referenced custom commands are registered
foreach (var user in aclUsers)
{
    foreach (var cmd in user.CustomCommandsAllowed.Concat(user.CustomCommandsDenied))
    {
        if (!customCommandManager.IsCustomCommandRegistered(cmd))
            throw new InvalidOperationException(
                $"ACL references unregistered custom command '{cmd}' for user '{user.Name}'. Load the module first.");
    }
}

Try / catch

try
{
    server = new GarnetServer(commandLineArgs, loggerFactory);
}
catch (GarnetException ex) when (ex.Message.Contains("ACL strict mode"))
{
    logger.LogError(ex, "ACL references unresolved custom commands. Load modules or disable acl-strict-custom-commands.");
    throw;
}

Prevention

When it happens

Trigger: An ACL configuration grants or denies a custom command (via CustomCommandsAllowed or CustomCommandsDenied) for a user, but no loaded Garnet module has registered that command name. With AclStrictCustomCommands=true, this is treated as a fatal startup error.

Common situations: Deploying an ACL file that references module commands before loading the module; typos in custom command names in the ACL file; upgrading a module that renamed or removed a command without updating the ACL; developing custom modules where the command registration name differs from the ACL rule.

Related errors


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