seerge/g-helper · error · IOException

{name} control device was not found on your machine.

Error message

{name} control device was not found on your machine.

What it means

Thrown by the WindowsUsbProvider(vendorId, productId, maxFeatureReportLength, name) constructor when no HID device with the given VID/PID reports a max feature report length at least maxFeatureReportLength. ASUS AniMe-matrix-style devices expose several HID interfaces; this overload selects the correct control interface by feature-report capacity using .First(x => x.GetMaxFeatureReportLength() >= maxFeatureReportLength). When nothing matches, .First() throws InvalidOperationException and the bare catch rethrows it as an IOException with the interpolated device name (e.g. 'Matrix control device was not found...'). Used by Device.SetProvider (Device.cs:44) for the AnimeMatrix communication device.

Source

Thrown at app/AnimeMatrix/Communication/Platform/WindowsUsbProvider.cs:44

            config.SetOption(OpenOption.Priority, 10);
            HidStream = HidDevice.Open(config);
            HidStream.ReadTimeout = timeout;
            HidStream.WriteTimeout = timeout;
        }

        public WindowsUsbProvider(ushort vendorId, ushort productId, int maxFeatureReportLength, string name = "Matrix")
            : base(vendorId, productId)
        {
            try
            {
                HidDevice = DeviceList.Local
                    .GetHidDevices(vendorId, productId)
                    .First(x => x.GetMaxFeatureReportLength() >= maxFeatureReportLength);
                Logger.WriteLine($"{name} Device: " + HidDevice.DevicePath + " " + HidDevice.GetMaxFeatureReportLength());
            }
            catch
            {
                throw new IOException($"{name} control device was not found on your machine.");
            }

            var config = new OpenConfiguration();
            config.SetOption(OpenOption.Interruptible, true);
            config.SetOption(OpenOption.Exclusive, false);
            config.SetOption(OpenOption.Priority, 10);

            HidStream = HidDevice.Open(config);
        }

        public override void Set(byte[] data)
        {
            WrapException(() =>
            {
                HidStream.SetFeature(data);
                HidStream.Flush();
            });
        }

View on GitHub (pinned to b9ba417f1b)

Solutions

  1. Confirm the machine actually has the AniMe matrix / supported device and that it appears in Device Manager as an HID device with the expected VID/PID (ASUS VID 0x0B05).
  2. Enumerate all GetHidDevices(vendorId, productId) and log each GetMaxFeatureReportLength() to see whether any interface meets the threshold (mirrors the Logger.WriteLine already on line 40).
  3. Lower or correct maxFeatureReportLength if the device interface changed across a firmware/driver revision.
  4. Ensure no other application holds the control interface exclusively, then reconstruct the provider.
  5. Treat a missing matrix device as a normal 'unsupported' condition rather than a fatal error (Device.SetProvider is virtual and already guarded with _usbProvider null checks downstream).
  6. Switch .First() to .FirstOrDefault() with a null check so the message states which threshold failed.

Example fix

// before
HidDevice = DeviceList.Local.GetHidDevices(vendorId, productId)
    .First(x => x.GetMaxFeatureReportLength() >= maxFeatureReportLength);
// after
HidDevice = DeviceList.Local.GetHidDevices(vendorId, productId)
    .FirstOrDefault(x => x.GetMaxFeatureReportLength() >= maxFeatureReportLength);
if (HidDevice is null)
    throw new IOException($"{name} control device (VID=0x{vendorId:X4} PID=0x{productId:X4}, featureReport >= {maxFeatureReportLength}) was not found on your machine.");
Defensive patterns

Strategy: validation

Validate before calling

// Mirror the constructor's feature-report-length filter before building the provider.
bool IsMatrixPresent(ushort vid, ushort pid, int minFeatureReportLength) =>
    HidSharp.DeviceList.Local.GetHidDevices(vid, pid)
        .Any(d =>
        {
            try { return d.GetMaxFeatureReportLength() >= minFeatureReportLength; }
            catch { return false; } // GetMaxFeatureReportLength can throw on some interfaces
        });

// Use it before constructing:
// if (!IsMatrixPresent(_vendorId, _productId, _maxFeatureReportLength)) { return; }

Try / catch

// Device.SetProvider constructs directly; wrap it to make absence non-fatal:
try
{
    _usbProvider = new WindowsUsbProvider(_vendorId, _productId, _maxFeatureReportLength, LogName);
}
catch (IOException ex)
{
    Logger.WriteLine($"{LogName} unavailable: {ex.Message}");
    _usbProvider = null;
}

Prevention

When it happens

Trigger: Constructing 'new WindowsUsbProvider(vendorId, productId, maxFeatureReportLength, name)' when DeviceList.Local.GetHidDevices(vendorId, productId) returns devices but none has GetMaxFeatureReportLength() >= maxFeatureReportLength, or returns no devices at all. The threshold (e.g. >= 128 in SlashDevice.cs:150) is what distinguishes this overload from error [0], which keys on DevicePath instead. .First() throwing InvalidOperationException is the immediate trigger; the catch masks it.

Common situations: The laptop has no AniMe matrix hardware (the matrix-only product variant is absent); the matrix device is present but the driver is not exposing its feature report length; the device went to sleep or was disconnected; the machine is a non-supported ASUS model so the expected VID/PID is absent; HidSharp returned a stale/empty enumeration after suspend/resume; another process holds the interface. Developers hit this when reusing the provider on unsupported hardware or after a Windows update reset the HID driver.

Related errors


AI-assisted analysis of seerge/g-helper@b9ba417f1b (2026-08-13). Data as JSON: /api/errors/2ff150b860ae3118. Report an issue: GitHub.