microsoft/garnet · error · GarnetException
CustomTransaction name is null
Error message
CustomTransaction name is null
What it means
Thrown by the CustomTransaction constructor when a module registers a custom transaction command with a null name string. The constructor (reached via CustomCommandManager.Register) guards explicitly because the next statement calls name.ToUpperInvariant(), which would otherwise throw an opaque NullReferenceException. It is a fail-fast programming-error check on the internal module-registration API surface.
Source
Thrown at libs/server/Custom/CustomTransaction.cs:21
using System;
using Garnet.common;
namespace Garnet.server
{
class CustomTransaction : ICustomCommand
{
public byte[] Name { get; }
public readonly string NameStr;
public readonly byte id;
public readonly int arity;
public readonly Func<CustomTransactionProcedure> proc;
internal CustomTransaction(string name, byte id, int arity, Func<CustomTransactionProcedure> proc)
{
if (name == null)
throw new GarnetException("CustomTransaction name is null");
NameStr = name.ToUpperInvariant();
this.Name = System.Text.Encoding.ASCII.GetBytes(NameStr);
this.id = id;
this.arity = arity;
this.proc = proc ?? throw new GarnetException("CustomTransactionProcedure is null");
}
}
}View on GitHub (pinned to 951b0fc683)
Solutions
- Pass a non-null, non-empty command name string to the registration call.
- If the name comes from configuration, validate it is non-null before registering and log a clear startup error.
- Search the call site 'new CustomTransaction(...)' and trace the name argument back to its source.
Example fix
// before
var txnId = customCommandManager.Register(config.TransactionName, MakeProc, info);
// after
if (string.IsNullOrEmpty(config.TransactionName))
throw new InvalidOperationException("Custom transaction name missing in config.");
var txnId = customCommandManager.Register(config.TransactionName, MakeProc, info); Defensive patterns
Strategy: validation
Validate before calling
// Validate before registering a custom transaction
if (string.IsNullOrEmpty(name))
throw new ArgumentException("Custom transaction name must be non-null and non-empty.", nameof(name));
customCommandManager.Register(name, proc, commandInfo, commandDocs); Try / catch
try {
customCommandManager.Register(name, proc, info);
} catch (GarnetException ex) when (ex.Message.Contains("name is null")) {
logger.LogError(ex, "Skipped custom transaction registration due to null name");
throw; // registration was never going to succeed; fix the caller
} Prevention
- Treat command names as required config and validate at startup before reaching the registration API.
- Enable nullable reference types so the compiler flags null name arguments at the call site.
When it happens
Trigger: Module/extension code calls the internal CustomCommandManager.Register(string name, Func<CustomTransactionProcedure> proc, ...) overload (or the equivalent RegisterCustomTransaction provider path) passing null as the command name. Register is internal, so this only originates from Garnet-embedded hosts or module code, never from a RESP client.
Common situations: Embedding Garnet in a custom host and wiring a custom transaction whose name was read from config that resolved to null; a refactor that drops the name argument; a unit test that constructs CustomTransaction directly with a null literal.
Related errors
- Unknown custom command '{name}' (not registered with any loa
- ACL strict mode: {unresolved.Count} unresolved (user, custom
AI-assisted analysis of microsoft/garnet@951b0fc683 (2026-08-13).
Data as JSON: /api/errors/2a3411aea0f85628.
Report an issue: GitHub.