{"record":{"id":"7e2081ebf2c77b95","repo":"microsoft/FASTER","slug":"asyncreadrecordobjectstomemory-invalid-for-7e2081","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/VarLenBlittableAllocator.cs","lineNumber":433,"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            return true;\n        }\n\n        public override ref Key GetContextRecordKey(ref AsyncIOContext<Key, Value> ctx)\n        {\n            return ref GetKey((long)ctx.record.GetValidPointer());\n        }\n","sourceCodeStart":415,"sourceCodeEnd":451,"githubUrl":"https://github.com/microsoft/FASTER/blob/321d872eabda6a0345c8bd76419f89723ed864ae/cs/src/core/Allocator/VarLenBlittableAllocator.cs#L415-L451","documentation":"VarLenBlittableAllocator stores records inline in sector-aligned memory pages and never keeps key/value objects in an object log, so the asynchronous object-deserialization read path is meaningless for it. The allocator deliberately overrides AsyncReadRecordObjectsToMemory to throw InvalidOperationException as an internal misuse guard. This indicates the caller expected an IObjectAllocator-style read path on a blittable allocator.","triggerScenarios":"An async page-read continuation or ReadInternal path requests async object materialization (AsyncReadRecordObjectsToMemory) while hlog is a VarLenBlittableAllocator/FasterLog-style blittable store. This is usually reached through internal plumbing (e.g. epoch-resumed async IO continuation) rather than a user API, typically from a mis-typed generic instantiation or code written for ObjectAllocator<...> being run against blittable types.","commonSituations":"Writing custom session/scan code that calls allocator internals copied from an ObjectsAllocator sample; generic helpers parameterized to work with both blittable and object allocators that assume the object-read API exists; upgrading FASTER versions where the async path changed.","solutions":["Use the direct (blittable) read path — records live in memory pages, so read them via ReadAsync/AsyncReadRecord to memory and copy bytes, not via the objects API.","If you need key/value heap objects, use VarlenBlittableFetchAsync/GetNext-style APIs (or ConvertToRecord) on the scan iterator instead of the objects read path.","Re-check generic constraints: the helper should be constrained to the object allocator type when it depends on AsyncReadRecordObjectsToMemory.","This is an invariant violation — file a bug with a repro if it comes from stock FASTER APIs."],"exampleFix":"// before: object-allocator style read against blittable log\nallocator.AsyncReadRecordObjectsToMemory(fromLogical, numBytes, callback, context, result);\n// after: direct blittable read\nvar status = await fkv.ReadAsync(ref key, ref input, ref output, ctx, serialFn, sessionId);","handlingStrategy":"validation","validationCode":"// ensure the allocator is not blittable before using object-read APIs\nif (allocator is VarLenBlittableAllocator<Key, Value>)\n    throw new NotSupportedException(\"Use direct blittable read path, not AsyncReadRecordObjectsToMemory\");","typeGuard":"static bool IsBlittableAllocator<I, K, V>(BlittableAllocatorBase<I, K, V> a)\n    => a is VarLenBlittableAllocator<K, V>;","tryCatchPattern":null,"preventionTips":["Do not call allocator internals; use Fkv.ReadAsync and iterator APIs","Constrain generic helpers to the allocator type whose APIs they use","When sharing code between object and blittable allocators, branch on allocator type first"],"tags":["blittable","allocator","unsupported-operation","internal-api"],"backgroundTag":"unsupported-operation","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"}