memstechtips/Winhance · critical · OperationCanceledException
DISM operation timed out after {HardTimeoutSeconds}s
Error message
DISM operation timed out after {HardTimeoutSeconds}s What it means
OperationCanceledException thrown by DismSessionManager.ExecuteAsync<T> when a native DISM call (run on a pooled thread under a single-semaphore lock) does not complete within the 30-second HardTimeoutSeconds deadline. Native DISM cannot be cancelled via CancellationToken, so Task.WhenAny races the work task against a 30s delay; if the delay wins, the thread is abandoned and the exception thrown to abort the caller.
Source
Thrown at src/Winhance.Infrastructure/Features/Common/Utilities/DismSessionManager.cs:77
log?.Invoke("[DismSession] Calling DismCloseSession...");
DismApi.DismCloseSession(session);
log?.Invoke("[DismSession] DismCloseSession done");
}
}
finally
{
log?.Invoke("[DismSession] Calling DismShutdown...");
DismApi.DismShutdown();
log?.Invoke("[DismSession] DismShutdown done");
}
}, ct);
var timeoutTask = Task.Delay(TimeSpan.FromSeconds(HardTimeoutSeconds), ct);
if (await Task.WhenAny(workTask, timeoutTask).ConfigureAwait(false) == timeoutTask)
{
log?.Invoke($"[DismSession] HARD TIMEOUT after {HardTimeoutSeconds}s — native DISM call is unresponsive, abandoning thread");
throw new OperationCanceledException($"DISM operation timed out after {HardTimeoutSeconds}s");
}
return await workTask.ConfigureAwait(false);
}
catch (OperationCanceledException)
{
log?.Invoke($"[DismSession] Operation cancelled/timed out in ExecuteAsync<T>");
throw;
}
catch (Exception ex)
{
log?.Invoke($"[DismSession] EXCEPTION in ExecuteAsync<T>: {ex.GetType().Name}: {ex.Message}");
throw;
}
finally
{
_lock.Release();
log?.Invoke($"[DismSession] Semaphore released. Total elapsed={sw.ElapsedMilliseconds}ms");
View on GitHub (pinned to f23d554eb2)
Solutions
- Retry once after a reboot — a transient DISM hang often clears when the servicing stack resets.
- Move the image to a local fast drive (avoid network/USB sources) and retry.
- Run `DISM /Online /Cleanup-Image /RestoreHealth` and `sfc /scannow` to repair a corrupt servicing stack, then retry.
- If the image is large and the 30s deadline is genuinely too short on this hardware, raise HardTimeoutSeconds (note: it is a const — make it configurable).
- Ensure no antivirus is scanning the image during the DISM call (add an exclusion).
Example fix
// before: hard-coded 30s, thread abandoned on timeout
private const int HardTimeoutSeconds = 30;
if (await Task.WhenAny(workTask, timeoutTask).ConfigureAwait(false) == timeoutTask)
throw new OperationCanceledException($"DISM operation timed out after {HardTimeoutSeconds}s");
// after: configurable timeout, longer for known-slow operations
private static int HardTimeoutSeconds => AppContext.GetData("DISM_HARD_TIMEOUT") is string s && int.TryParse(s, out var v) ? v : 60;
if (await Task.WhenAny(workTask, timeoutTask).ConfigureAwait(false) == timeoutTask)
throw new OperationCanceledException($"DISM operation timed out after {HardTimeoutSeconds}s. The image may be corrupt or on slow storage."); Defensive patterns
Strategy: retry
Validate before calling
// Pre-flight: ensure the image is local and the servicing stack is healthy.
bool IsHealthyForNativeDism(string imagePath) =>
_fileSystemService.FileExists(imagePath) && !imagePath.StartsWith(@"\\"); Try / catch
catch (OperationCanceledException ex) when (ex.Message.Contains("DISM operation timed out"))
{
// After a hard timeout the DISM engine may be wedged; advise a reboot before any retry.
// Do NOT immediately retry on the same image — that re-wedges the same pooled thread.
} Prevention
- Keep images on local fast storage for native DISM calls.
- Exclude the image/working folder from antivirus scans.
- Repair the servicing stack periodically (sfc + DISM /RestoreHealth).
- Make HardTimeoutSeconds configurable for slow hardware/large images.
When it happens
Trigger: ExecuteAsync<T> acquires the global DISM semaphore, Task.Run's the native call (DismInitialize + the action + DismShutdown), and Task.WhenAny returns the timeoutTask first. Happens when DISM hangs on a corrupt image, a network-backed source, a locked file, or a servicing stack in a bad state. Also if the system is under heavy I/O and DISM is slow to respond.
Common situations: The WIM/image path is on a slow network share. The image is corrupted and DISM loops internally. Another DISM process holds resources. The 30s budget is too short for a large image on a slow machine. Antivirus is scanning the image and slowing DISM I/O.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- DISM {operation} failed with HRESULT 0x{hr:X8}
- DISM Export-Driver failed with exit code: {exitCode}
- DISM failed with exit code: {exitCode}
- Insufficient disk space on {driveName} for {operationName}.
- Could not delete the existing working directory '{workingDir
AI-assisted analysis of memstechtips/Winhance@f23d554eb2 (2026-08-13).
Data as JSON: /api/errors/927df7dbd41fdbfb.
Report an issue: GitHub.