You're in Services.msc, right-click a service, go to Recovery tab, and the whole thing is grayed out. Or you try sc failure in Command Prompt and get:
ERROR: 0x438 - Failure actions can only be set for Win32 services, not for drivers
This hits when you're targeting a kernel driver, not a regular user-mode service. Common triggers: you're building a custom driver, testing a storage filter driver, or you inherited a server where someone installed a third-party driver (like a backup agent or VPN filter) and you want it to restart on failure. Windows simply won't let you set recovery actions on anything that loads at boot as a driver.
Why this happens
Windows separates services into two buckets: Win32 services (like spooler or wuauserv) and kernel drivers (like ndis or disk). The Recovery tab in Services.msc and the sc failure command only work on the first bucket. The Service Control Manager (SCM) enforces this by checking the service type. If the type is SERVICE_KERNEL_DRIVER (0x1) or SERVICE_FILE_SYSTEM_DRIVER (0x2), it rejects any attempt to write failure actions.
That check is hardcoded in services.exe. There's no registry hack to bypass it. You could change the service type to a Win32 service, but then the driver won't load at boot correctly—you'd break more than you fix.
The real fix: don't set failure actions on drivers
Kernel drivers aren't meant to be babysat with restart actions. If a driver crashes, Windows already handles it via the bugcheck path (BSOD) or the Driver Verifier. Trying to force a restart can cause a reboot loop if the driver fails at boot.
If you absolutely need the driver to recover, you have three options. Pick based on what you're doing.
Option 1: Use a wrapper service (most common)
Don't set the driver itself as a service. Instead, create a Win32 service that loads the driver on start and monitors it. Here's the pattern:
- Write a simple executable (PowerShell script works for testing) that calls
sc start MyDriver. - Create a service that runs that script at boot.
- Set recovery actions on that service, not the driver.
For example, create a service named DriverWrapper:
sc create DriverWrapper binPath= "cmd.exe /c sc start MyDriver" start= auto
sc failure DriverWrapper reset= 86400 actions= restart/5000/restart/5000/restart/5000
After running these, you should see [SC] ChangeServiceConfig2 SUCCESS. That's the confirmation you're looking for.
Option 2: Handle recovery inside the driver
If you wrote the driver, add a watchdog in the driver itself. Use a timer (WDK timer) to check if a critical thread hung, then reset the hardware or reinitialize the device. This is the proper kernel-level solution. It's more work, but it's the only way to get true self-healing for a driver.
Option 3: Use a scheduled task to restart the driver
For a quick workaround, create a task in Task Scheduler that runs when the driver's event log shows an error. Set the trigger to Event ID 7011 or 7023 from Service Control Manager, then have the task run sc stop MyDriver and sc start MyDriver. This isn't as reliable as a wrapper, but it works if the driver doesn't crash the whole system.
What to check if it still fails
If you tried the wrapper service and still get 0x438, check the service type you created. Run:
sc qc DriverWrapper
Look at the SERVICE_TYPE line. It should say WIN32_OWN_PROCESS or WIN32_SHARE_PROCESS. If it says KERNEL_DRIVER, you messed up the binPath—the SCM guessed wrong. Fix it with:
sc config DriverWrapper type= own
Also, if you're on Windows 10 1809 or earlier, the actions= syntax used to be different. Try using the /failure switch in the older Resource Kit tools, or upgrade to a supported build. Server 2016 and older need the sc failure command with reset= before actions=.
One last sanity check: open Services.msc and confirm your wrapper service appears under Extended view. If it's missing, you created it as a driver. Delete it and start over with type= own in the sc create command.
Bottom line: Windows won't let you set failure actions on drivers, and that's by design. Don't fight it. Use a wrapper or handle it in the driver code. You'll save yourself an evening of cursing at the command line.