microsoft/garnet · error · ArgumentNullException
Value cannot be null. (Parameter 'functions')
Error message
Value cannot be null. (Parameter 'functions')
What it means
NewSession requires a non-null TFunctions (ISessionFunctions) callback instance because every Tsavorite operation (Read, Upsert, RMW, Delete, compaction callbacks) dispatches through it. Passing null would cause NullReferenceException deep inside the operation pipeline, so the constructor validates upfront with a standard ArgumentNullException. The check uses nameof(functions) so the parameter name appears in the exception.
Source
Thrown at libs/storage/Tsavorite/cs/src/core/ClientSession/ManageClientSessions.cs:37
/// <param name="functions">Callback functions</param>
/// <param name="enableConsistentRead">Enable consistent read context</param>
/// <param name="readCopyOptions"><see cref="ReadCopyOptions"/> for this session; override those specified at TsavoriteKV level, and may be overridden on individual Read operations</param>
/// <param name="initialIORecordSize">Initial IO record size for disk reads in this session;
/// <see cref="KVSettings.UseDefaultInitialIORecordSize"/> means inherit from the store-level setting, and may be overridden on individual Read operations via <see cref="ReadOptions.InitialIORecordSize"/>.</param>
/// <returns>Session instance</returns>
public ClientSession<TKey, TInput, TOutput, TContext, TFunctions, TStoreFunctions, TAllocator> NewSession<TKey, TInput, TOutput, TContext, TFunctions>(
TFunctions functions,
bool enableConsistentRead = false,
ReadCopyOptions readCopyOptions = default,
int initialIORecordSize = KVSettings.UseDefaultInitialIORecordSize)
where TKey : IKey
#if NET9_0_OR_GREATER
, allows ref struct
#endif
where TFunctions : ISessionFunctions<TInput, TOutput, TContext>
{
if (functions == null)
throw new ArgumentNullException(nameof(functions));
int sessionID = Interlocked.Increment(ref maxSessionID);
var ctx = new TsavoriteExecutionContext<TInput, TOutput, TContext>(sessionID);
ctx.MergeReadCopyOptions(ReadCopyOptions, readCopyOptions);
ctx.InitialIORecordSize = initialIORecordSize;
if (RevivificationManager.IsEnabled)
{
if (_activeSessions == null)
_ = Interlocked.CompareExchange(ref _activeSessions, [], null);
}
var session = new ClientSession<TKey, TInput, TOutput, TContext, TFunctions, TStoreFunctions, TAllocator>(this, ctx, functions, enableConsistentRead);
lock (_activeSessions)
_activeSessions.Add(sessionID, new SessionInfo { session = session, isActive = true });
return session;
}
/// <summary>View on GitHub (pinned to 951b0fc683)
Solutions
- Ensure the TFunctions argument passed to NewSession is a properly constructed instance before the call.
- If using DI, register the ISessionFunctions implementation in the container so it resolves to a non-null instance.
- Add a null check or ArgumentNullException.ThrowIfNull in your own session-creation wrapper before delegating to NewSession.
Example fix
// before (throws if factory.Create() returns null)
var session = store.NewSession<TKey, TInput, TOutput, TContext, MyFunctions>(factory.Create());
// after
var functions = factory.Create() ?? throw new InvalidOperationException("Functions factory returned null");
var session = store.NewSession<TKey, TInput, TOutput, TContext, MyFunctions>(functions); Defensive patterns
Strategy: validation
Validate before calling
// Validate functions before creating the session ArgumentNullException.ThrowIfNull(functions); var session = store.NewSession<TKey, TInput, TOutput, TContext, TFunctions>(functions);
Try / catch
// Wrap session creation if the source of functions is unreliable
try
{
var session = store.NewSession<...>(functions);
}
catch (ArgumentNullException ex) when (ex.ParamName == "functions")
{
logger.LogError("Session functions were not provided");
throw;
} Prevention
- Register ISessionFunctions implementations in your DI container so they always resolve to non-null instances.
- Use ArgumentNullException.ThrowIfNull(functions) before calling NewSession in your own factory methods.
- Avoid conditional assignment of the functions variable — initialize it at declaration.
When it happens
Trigger: Calling tsavoriteKV.NewSession<...>(functions: null) or a generic factory that resolves the functions argument to null (e.g. a DI container that failed to register the ISessionFunctions, or a default(TFunctions) that is a null reference for class-based functions).
Common situations: Dependency injection misconfiguration where the ISessionFunctions service is not registered; conditional session creation where the functions variable is assigned in a branch that was not taken; passing a struct functions type via a nullable wrapper that yields null.
Related errors
- InPlaceWriter(ReadOnlySpan<byte> value) is not supported in
- InPlaceWriter(IHeapObject value) is not supported in this IS
- GetRMWModifiedFieldInfo is not supported in this ISessionFun
- GetRMWInitialFieldInfo is not supported in this ISessionFunc
- GetUpsertFieldInfo(ReadOnlySpan<byte> value) is not supporte
AI-assisted analysis of microsoft/garnet@951b0fc683 (2026-08-13).
Data as JSON: /api/errors/0b42d27d8144051f.
Report an issue: GitHub.