{"record":{"id":"99fabc8247e15c9b","repo":"microsoft/FASTER","slug":"logsettings-objectlogdevice-needs-to-be-specified-e-g-use","errorCode":null,"errorMessage":"LogSettings.ObjectLogDevice needs to be specified (e.g., use Devices.CreateLogDevice, AzureStorageDevice, or NullDevice)","messagePattern":"LogSettings\\.ObjectLogDevice needs to be specified \\(e\\.g\\., use Devices\\.CreateLogDevice, AzureStorageDevice, or NullDevice\\)","errorType":"exception","errorClass":"FasterException","httpStatus":null,"severity":"error","filePath":"cs/src/core/Allocator/GenericAllocator.cs","lineNumber":52,"sourceCode":"        // Tail offsets per segment, in object log\n        public readonly long[] segmentOffsets;\n        // Record sizes\n        private static readonly int recordSize = Unsafe.SizeOf<Record<Key, Value>>();\n        private readonly SerializerSettings<Key, Value> SerializerSettings;\n        private readonly bool keyBlittable = Utility.IsBlittable<Key>();\n        private readonly bool valueBlittable = Utility.IsBlittable<Value>();\n\n        private readonly OverflowPool<Record<Key, Value>[]> overflowPagePool;\n\n        public GenericAllocator(LogSettings settings, SerializerSettings<Key, Value> serializerSettings, IFasterEqualityComparer<Key> comparer, \n                Action<long, long> evictCallback = null, LightEpoch epoch = null, Action<CommitInfo> flushCallback = null, ILogger logger = null)\n            : base(settings, comparer, evictCallback, epoch, flushCallback, logger)\n        {\n            overflowPagePool = new OverflowPool<Record<Key, Value>[]>(4);\n\n            if (settings.ObjectLogDevice == null)\n            {\n                throw new FasterException(\"LogSettings.ObjectLogDevice needs to be specified (e.g., use Devices.CreateLogDevice, AzureStorageDevice, or NullDevice)\");\n            }\n\n            SerializerSettings = serializerSettings ?? new SerializerSettings<Key, Value>();\n\n            if ((!keyBlittable) && (settings.LogDevice as NullDevice == null) && ((SerializerSettings == null) || (SerializerSettings.keySerializer == null)))\n            {\n#if DEBUG\n                if (typeof(Key) != typeof(byte[]) && typeof(Key) != typeof(string))\n                    Debug.WriteLine(\"Key is not blittable, but no serializer specified via SerializerSettings. Using (slow) DataContractSerializer as default.\");\n#endif\n                SerializerSettings.keySerializer = ObjectSerializer.Get<Key>();\n            }\n\n            if ((!valueBlittable) && (settings.LogDevice as NullDevice == null) && ((SerializerSettings == null) || (SerializerSettings.valueSerializer == null)))\n            {\n#if DEBUG\n                if (typeof(Value) != typeof(byte[]) && typeof(Value) != typeof(string))\n                    Debug.WriteLine(\"Value is not blittable, but no serializer specified via SerializerSettings. Using (slow) DataContractSerializer as default.\");","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/microsoft/FASTER/blob/321d872eabda6a0345c8bd76419f89723ed864ae/cs/src/core/Allocator/GenericAllocator.cs#L34-L70","documentation":"Thrown from the GenericAllocator constructor when the allocator supports non-blittable (object) keys/values but LogSettings.ObjectLogDevice was not set. Since keys or values live as managed objects, FASTER needs a separate object log device to persist them, distinct from the main LogDevice. Without it the allocator cannot be constructed at all, so it fails immediately at instance creation.","triggerScenarios":"Creating a FASTER instance (f(kv, ...) with class/struct key or value types containing object references) via CreateKVSettings/LogSettings where LogDevice is set but ObjectLogDevice is left null, with LogDevice not a NullDevice.","commonSituations":"Using class-type keys/values without calling Devices.CreateLogDevice for a second device; copying blittable-only sample config to an object-based workload; forgetting NullDevice.Instance when no persistence is wanted.","solutions":["Set LogSettings.ObjectLogDevice = Devices.CreateLogDevice(path) for a dedicated object log file.","If you do not want persistence, use LogSettings.ObjectLogDevice = new NullDevice() (and possibly a NullDevice for LogDevice too).","Centralize device setup in one config factory so both LogDevice and ObjectLogDevice are always assigned for object-based KV types."],"exampleFix":"// before\nvar logSettings = new LogSettings { LogDevice = Devices.CreateLogDevice(\"data.log\") };\n\n// after\nvar logSettings = new LogSettings\n{\n    LogDevice = Devices.CreateLogDevice(\"data.log\"),\n    ObjectLogDevice = Devices.CreateLogDevice(\"data.obj.log\") // or new NullDevice()\n};","handlingStrategy":"validation","validationCode":"// Validate settings before constructing FASTER\nif (settings.ObjectLogDevice == null)\n    settings.ObjectLogDevice = Devices.CreateLogDevice(\"data.obj.log\", preallocateFile: false);\n// or explicitly: settings.ObjectLogDevice = new NullDevice();","typeGuard":"static bool HasObjectLog(LogSettings s) => s.ObjectLogDevice != null;","tryCatchPattern":"try\n{\n    var f = fkv.CreateNewInstance(storeSettings);\n}\ncatch (FasterException ex) when (ex.Message.Contains(\"ObjectLogDevice\"))\n{\n    storeSettings.LogSettings.ObjectLogDevice = Devices.CreateLogDevice(\"data.obj.log\", preallocateFile: false);\n    var f = fkv.CreateNewInstance(storeSettings);\n}","preventionTips":["Use a single settings-factory that always sets both LogDevice and ObjectLogDevice for object-typed KV pairs.","Add a startup assertion that ObjectLogDevice != null when typeof(Key) or typeof(Value) contains reference types.","When only testing in memory, explicitly use NullDevice for both devices rather than leaving fields null."],"tags":["faster","configuration","devices","object-log"],"backgroundTag":"missing-required-config-field","analyzedSha":"321d872eabda6a0345c8bd76419f89723ed864ae","analyzedAt":"2026-09-15T22:18:00.693Z","contentChangedAt":"2026-09-15T22:18:00.693Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}