{"record":{"id":"df559233cc29eeb4","repo":"microsoft/FASTER","slug":"asyncreadrecordobjectstomemory-invalid-for","errorCode":null,"errorMessage":"AsyncReadRecordObjectsToMemory invalid for BlittableAllocator","messagePattern":"AsyncReadRecordObjectsToMemory invalid for BlittableAllocator","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"cs/src/core/Allocator/BlittableAllocator.cs","lineNumber":328,"sourceCode":"            ulong alignedSourceAddress, int destinationPageIndex, uint aligned_read_length,\n            DeviceIOCompletionCallback callback, PageAsyncReadResult<TContext> asyncResult, IDevice device, IDevice objlogDevice)\n        {\n            device.ReadAsync(alignedSourceAddress, (IntPtr)pointers[destinationPageIndex],\n                aligned_read_length, callback, asyncResult);\n        }\n\n        /// <summary>\n        /// Invoked by users to obtain a record from disk. It uses sector aligned memory to read \n        /// the record efficiently into memory.\n        /// </summary>\n        /// <param name=\"fromLogical\"></param>\n        /// <param name=\"numBytes\"></param>\n        /// <param name=\"callback\"></param>\n        /// <param name=\"context\"></param>\n        /// <param name=\"result\"></param>\n        protected override void AsyncReadRecordObjectsToMemory(long fromLogical, int numBytes, DeviceIOCompletionCallback callback, AsyncIOContext<Key, Value> context, SectorAlignedMemory result = default)\n        {\n            throw new InvalidOperationException(\"AsyncReadRecordObjectsToMemory invalid for BlittableAllocator\");\n        }\n\n        /// <summary>\n        /// Retrieve objects from object log\n        /// </summary>\n        /// <param name=\"record\"></param>\n        /// <param name=\"ctx\"></param>\n        /// <returns></returns>\n        protected override bool RetrievedFullRecord(byte* record, ref AsyncIOContext<Key, Value> ctx)\n        {\n            ctx.key = GetKey((long)record);\n            ctx.value = GetValue((long)record);\n            return true;\n        }\n\n        /// <summary>\n        /// Whether KVS has keys to serialize/deserialize\n        /// </summary>","sourceCodeStart":310,"sourceCodeEnd":346,"githubUrl":"https://github.com/microsoft/FASTER/blob/321d872eabda6a0345c8bd76419f89723ed864ae/cs/src/core/Allocator/BlittableAllocator.cs#L310-L346","documentation":"AsyncReadRecordObjectsToMemory exists to hydrate object references from the object log; BlittableAllocator stores fixed-size binary records and has no per-record objects, so it deliberately does not implement this operation and throws InvalidOperationException. Calling it is always a caller mistake - the wrong allocator path was used.","triggerScenarios":"Invoking ReadAsync with the objects path / internal ReadRecordObjects variant on a FasterKV configured with blittable (non-ICanSerialize/non-object) Key/Value types.","commonSituations":"Generic or reflection-based helper code calling AsyncReadRecordObjectsToMemory regardless of allocator type; switching Key/Value from class to struct types (object to blittable) without updating read logic.","solutions":["Use the normal ReadAsync API; for blittable allocators records are returned directly without object hydration.","If you need object-log semantics, configure Key/Value as classes so the ObjectAllocator (not BlittableAllocator) is used.","Remove/branch code paths that call the objects-to-memory read variant when IDevice/log is blittable."],"exampleFix":"// before\n// blittable store (struct Key/Value)\nstore.Log.AsyncReadRecordObjectsToMemory(addr, len, callback, ctx, result);\n\n// after\nvar (status, output) = (await session.ReadAsync(key)).Complete(); // standard read path for blittable records","handlingStrategy":"validation","validationCode":"if (typeof(Key).IsValueType || typeof(Value).IsValueType)\n    throw new InvalidOperationException(\"Blittable store: use ReadAsync, not object-hydration reads\");","typeGuard":"bool IsObjectAllocator<FasterLog>(FasterKV<K, V> store) => typeof(K).IsClass || typeof(V).IsClass; // object-hydration APIs only valid when types are classes","tryCatchPattern":"try { /* object read path */ }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"invalid for BlittableAllocator\")) { /* switch to standard ReadAsync */ }","preventionTips":["Use the public ReadAsync API; avoid internal objects-to-memory paths unless using the ObjectAllocator.","Keep read code paths aligned with whether Key/Value are classes or structs.","Avoid reflection-driven generic read helpers that assume object logs."],"tags":["csharp","faster","unsupported-operation","blittable"],"backgroundTag":"unsupported-operation","analyzedSha":"321d872eabda6a0345c8bd76419f89723ed864ae","analyzedAt":"2026-09-15T22:18:00.693Z","contentChangedAt":"2026-09-15T22:18:00.693Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}