microsoft/FASTER · error · FasterException

Cannot use LocalStorageDevice from non-Windows OS platform…

Error message

Cannot use LocalStorageDevice from non-Windows OS platform, use ManagedLocalStorageDevice instead.

What it means

LocalStorageDevice uses Windows-native APIs (IO completion ports, Native32 Win32 calls) and therefore only works on Windows. On Linux/macOS the constructor immediately throws, directing developers to ManagedLocalStorageDevice, which uses the cross-platform .NET file API.

Solutions

  1. Use Devices.CreateLogDevice(...), which on .NET (Core) selects ManagedLocalStorageDevice on non-Windows platforms.
  2. Explicitly instantiate ManagedLocalStorageDevice for cross-platform local storage.
  3. Guard device creation with RuntimeInformation checks if you must construct devices manually per OS.

Example fix

// before
var device = new LocalStorageDevice("/data/store.log");
// after
var device = new ManagedLocalStorageDevice("/data/store.log");
Defensive patterns

Strategy: validation

Validate before calling

var device = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
    ? new LocalStorageDevice(path)
    : new ManagedLocalStorageDevice(path);

Type guard

static bool IsWindows() => RuntimeInformation.IsOSPlatform(OSPlatform.Windows);

Prevention

When it happens

Trigger: Calling new LocalStorageDevice(...) (or Devices.CreateLogDevice choosing it) on a non-Windows OS, detected via RuntimeInformation.IsOSPlatform(OSPlatform.Windows) == false.

Common situations: Deploying a Windows-developed FASTER application to Linux containers/Kubernetes without changing the device factory; CI running on Linux agents.

Understand the failure class

Background: "unsupported platform" / "not supported on this platform" errors: what they mean and how to fix them — this error's family across 47 libraries.

Related errors


AI-assisted analysis of microsoft/FASTER@321d872eab (2026-09-15). Data as JSON: /api/errors/9a626896a9b1983f. Report an issue: GitHub.

Appendix: source

Thrown at cs/src/core/Device/LocalStorageDevice.cs:107

        /// <param name="deleteOnClose"></param>
        /// <param name="disableFileBuffering"></param>
        /// <param name="capacity">The maximum number of bytes this storage device can accommondate, or CAPACITY_UNSPECIFIED if there is no such limit </param>
        /// <param name="recoverDevice">Whether to recover device metadata from existing files</param>
        /// <param name="initialLogFileHandles">Optional set of preloaded safe file handles, which can speed up hydration of preexisting log file handles</param>
        /// <param name="useIoCompletionPort">Whether we use IO completion port with polling</param>
        protected internal LocalStorageDevice(string filename,
                                      bool preallocateFile = false,
                                      bool deleteOnClose = false,
                                      bool disableFileBuffering = true,
                                      long capacity = Devices.CAPACITY_UNSPECIFIED,
                                      bool recoverDevice = false,
                                      IEnumerable<KeyValuePair<int, SafeFileHandle>> initialLogFileHandles = null,
                                      bool useIoCompletionPort = true)
                : base(filename, GetSectorSize(filename), capacity)
        {
            if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                throw new FasterException("Cannot use LocalStorageDevice from non-Windows OS platform, use ManagedLocalStorageDevice instead.");
            }

            if (filename.Length > Native32.WIN32_MAX_PATH - 11)     // -11 to allow for ".<segment>"
                throw new FasterException($"Path {filename} is too long");

            ThrottleLimit = 120;
            this.useIoCompletionPort = useIoCompletionPort;
            this._disposed = false;

            if (useIoCompletionPort)
            {
                ThreadPool.GetMaxThreads(out int workerThreads, out _);
                ioCompletionPort = Native32.CreateIoCompletionPort(new SafeFileHandle(new IntPtr(-1), false), IntPtr.Zero, UIntPtr.Zero, (uint)(workerThreads + NumCompletionThreads));
                for (int i = 0; i < NumCompletionThreads; i++)
                {
                    var thread = new Thread(() => new LocalStorageDeviceCompletionWorker().Start(ioCompletionPort, _callback))
                    {
                        IsBackground = true

View on GitHub (pinned to 321d872eab)