microsoft/garnet · error · ACLException
Unknown custom command '{name}' (not registered with any loa
Error message
Unknown custom command '{name}' (not registered with any loaded module) What it means
Thrown during ACL SETUSER (the retry-loop that applies ACL ops) when a newly-added entry in the user's CustomCommandsAllowed set does not match any registered custom command. The check is intentionally limited to names not already present in the pre-op allow/deny sets (so toggling legacy names does not false-positive), so it fires specifically for freshly-introduced, unregistered names - almost always a typo or a missing module.
Source
Thrown at libs/server/Resp/ACLCommands.cs:214
for (var i = 1; i < ops.Length; i++)
{
ACLParser.ApplyACLOpToUser(ref newUser, ops[i]);
}
// At SETUSER time modules are loaded; any newly-added per-name custom permission
// must resolve against CustomCommandManager. Unknown names here are almost always
// typos - fail closed.
var ccm = storeWrapper.customCommandManager;
if (ccm != null)
{
foreach (var name in newUser.CustomCommandsAllowed)
{
// A name already present in either pre-op set (allow/deny) is not "new" from
// the system's POV - only flag names absent from both presets and unregistered.
// This permits toggling (allow↔deny) of loose-loaded names without false-positive throws.
if (!preAllowed.Contains(name) && !preDenied.Contains(name) && !ccm.IsCustomCommandRegistered(name))
{
throw new ACLException($"Unknown custom command '{name}' (not registered with any loaded module)");
}
}
foreach (var name in newUser.CustomCommandsDenied)
{
if (!preAllowed.Contains(name) && !preDenied.Contains(name) && !ccm.IsCustomCommandRegistered(name))
{
throw new ACLException($"Unknown custom command '{name}' (not registered with any loaded module)");
}
}
}
}
while (!userHandle.TrySetUser(newUser, currentUser));
}
catch (ACLException exception)
{
// Abort command execution
while (!RespWriteUtils.TryWriteError($"ERR {exception.Message}", ref dcurr, dend))
SendAndReset();View on GitHub (pinned to 951b0fc683)
Solutions
- Correct the command name in the ACL rule to match the registered custom command exactly (case-sensitive).
- Ensure the module that registers the custom command is loaded before applying the ACL rule.
- List registered custom commands (e.g., via COMMAND DOCS / module introspection) to confirm the exact name.
Example fix
# before ACL SETUSER alice on >pass +mycuston # typo: should be mycustom # after ACL SETUSER alice on >pass +mycustom
Defensive patterns
Strategy: validation
Validate before calling
// Before issuing ACL SETUSER with custom command rules
foreach (var name in allowCustomNames) {
if (!storeWrapper.customCommandManager.IsCustomCommandRegistered(name))
throw new InvalidOperationException($"Refusing ACL rule: custom command '{name}' is not registered.");
} Try / catch
catch (ACLException ex) when (ex.Message.Contains("Unknown custom command")) {
// ACL rule referenced an unregistered name; surface to operator, do not persist the user change
logger.LogWarning("ACL SETUSER rejected: {Msg}", ex.Message);
} Prevention
- Load all modules before loading ACL files.
- Validate custom command names against the registered set before applying ACL rules.
- Note only newly-added names are checked; pre-existing names are grandfathered.
When it happens
Trigger: An ACL SETUSER rule adds a +<customname> allow entry where <customname> is not registered with CustomCommandManager and was not already in the user's allow/deny sets.
Common situations: Typing a custom command name wrong in an ACL rule; referencing a custom command from a module that is not loaded; applying an ACL file before the module defining the command has loaded (for names not already preset).
Related errors
- ACL strict mode: {unresolved.Count} unresolved (user, custom
- Unable to parse ACL rule {exception.Filename}:{exception.Lin
- ACL configuration file not set.
- {exception.Message}
- CustomTransaction name is null
AI-assisted analysis of microsoft/garnet@951b0fc683 (2026-08-13).
Data as JSON: /api/errors/df238f4a7628962a.
Report an issue: GitHub.