Skip to main content

Overview

The Windows Package Manager COM API uses a combination of status enums, HRESULT codes, and result information to report errors. Proper error handling ensures robust applications and helpful user feedback.

Error Patterns

Package Management Errors

Package operations return result objects with status enums and extended error codes:
public class InstallResult
{
    InstallResultStatus Status { get; }
    HRESULT ExtendedErrorCode { get; }
    UInt32 InstallerErrorCode { get; } // When Status == InstallError
    String CorrelationData { get; }
    Boolean RebootRequired { get; }
}

Configuration Errors

Configuration operations use IConfigurationUnitResultInformation:
public interface IConfigurationUnitResultInformation
{
    HRESULT ResultCode { get; }
    String Description { get; }
    String Details { get; }
    ConfigurationUnitResultSource ResultSource { get; }
}

Package Management Error Handling

Install Errors

var result = await manager.InstallPackageAsync(package, options);

switch (result.Status)
{
    case InstallResultStatus.Ok:
        Console.WriteLine("Installation successful");
        if (result.RebootRequired)
        {
            Console.WriteLine("Please reboot to complete installation");
        }
        break;
        
    case InstallResultStatus.InstallError:
        Console.WriteLine("Installer failed");
        Console.WriteLine($"Extended Error: 0x{result.ExtendedErrorCode:X8}");
        Console.WriteLine($"Installer Error Code: 0x{result.InstallerErrorCode:X}");
        
        // Common installer error codes
        switch (result.InstallerErrorCode)
        {
            case 0x80070005: // E_ACCESSDENIED
                Console.WriteLine("Access denied. Run as administrator.");
                break;
            case 0x80070643: // ERROR_INSTALL_FAILURE
                Console.WriteLine("Installation failed. Check installer logs.");
                break;
            case 0x80070BC9: // ERROR_SUCCESS_REBOOT_REQUIRED
                Console.WriteLine("Installation requires reboot.");
                break;
        }
        break;
        
    case InstallResultStatus.DownloadError:
        Console.WriteLine("Failed to download installer");
        Console.WriteLine($"Error: 0x{result.ExtendedErrorCode:X8}");
        
        // Check network connectivity
        if (result.ExtendedErrorCode == unchecked((int)0x80072EFD)) // WININET_E_CANNOT_CONNECT
        {
            Console.WriteLine("Cannot connect to server. Check network.");
        }
        break;
        
    case InstallResultStatus.BlockedByPolicy:
        Console.WriteLine("Installation blocked by group policy");
        break;
        
    case InstallResultStatus.PackageAgreementsNotAccepted:
        Console.WriteLine("Package agreements not accepted");
        Console.WriteLine("Set AcceptPackageAgreements = true");
        break;
        
    case InstallResultStatus.NoApplicableInstallers:
        Console.WriteLine("No installer available for this system");
        Console.WriteLine("Check architecture and OS version requirements");
        break;
        
    case InstallResultStatus.InvalidOptions:
        Console.WriteLine("Invalid install options provided");
        break;
        
    case InstallResultStatus.CatalogError:
        Console.WriteLine("Catalog error occurred");
        Console.WriteLine($"Error: 0x{result.ExtendedErrorCode:X8}");
        break;
        
    case InstallResultStatus.InternalError:
        Console.WriteLine("Internal error occurred");
        Console.WriteLine($"Error: 0x{result.ExtendedErrorCode:X8}");
        break;
        
    case InstallResultStatus.ManifestError:
        Console.WriteLine("Package manifest error");
        break;
}

Uninstall Errors

var result = await manager.UninstallPackageAsync(package, options);

switch (result.Status)
{
    case UninstallResultStatus.Ok:
        Console.WriteLine("Uninstallation successful");
        break;
        
    case UninstallResultStatus.UninstallError:
        Console.WriteLine("Uninstaller failed");
        Console.WriteLine($"Error Code: 0x{result.UninstallerErrorCode:X}");
        Console.WriteLine($"HRESULT: 0x{result.ExtendedErrorCode:X8}");
        break;
        
    case UninstallResultStatus.BlockedByPolicy:
        Console.WriteLine("Uninstall blocked by policy");
        break;
        
    case UninstallResultStatus.CatalogError:
        Console.WriteLine("Catalog error");
        break;
        
    case UninstallResultStatus.InternalError:
        Console.WriteLine("Internal error");
        break;
        
    case UninstallResultStatus.InvalidOptions:
        Console.WriteLine("Invalid options");
        break;
        
    case UninstallResultStatus.ManifestError:
        Console.WriteLine("Manifest error");
        break;
}

Catalog Errors

// Connection errors
var connectResult = await catalogRef.ConnectAsync();

if (connectResult.Status != ConnectResultStatus.Ok)
{
    switch (connectResult.Status)
    {
        case ConnectResultStatus.CatalogError:
            Console.WriteLine("Failed to connect to catalog");
            Console.WriteLine($"Error: 0x{connectResult.ExtendedErrorCode:X8}");
            break;
            
        case ConnectResultStatus.SourceAgreementsNotAccepted:
            Console.WriteLine("Source agreements not accepted");
            Console.WriteLine("Set AcceptSourceAgreements = true");
            break;
    }
    return;
}

// Search errors
var findResult = await catalog.FindPackagesAsync(options);

if (findResult.Status != FindPackagesResultStatus.Ok)
{
    switch (findResult.Status)
    {
        case FindPackagesResultStatus.CatalogError:
            Console.WriteLine("Catalog error during search");
            break;
            
        case FindPackagesResultStatus.BlockedByPolicy:
            Console.WriteLine("Search blocked by policy");
            break;
            
        case FindPackagesResultStatus.InvalidOptions:
            Console.WriteLine("Invalid search options");
            break;
            
        case FindPackagesResultStatus.InternalError:
            Console.WriteLine("Internal error");
            break;
            
        case FindPackagesResultStatus.AuthenticationError:
            Console.WriteLine("Authentication failed");
            Console.WriteLine("Check authentication credentials");
            break;
            
        case FindPackagesResultStatus.AccessDenied:
            Console.WriteLine("Access denied to catalog");
            break;
    }
    
    Console.WriteLine($"Extended Error: 0x{findResult.ExtendedErrorCode:X8}");
}

Configuration Error Handling

Opening Configuration Sets

var openResult = await processor.OpenConfigurationSetAsync(stream);

if (openResult.ResultCode != 0)
{
    Console.WriteLine("Failed to open configuration:");
    Console.WriteLine($"  HRESULT: 0x{openResult.ResultCode:X8}");
    
    if (!string.IsNullOrEmpty(openResult.Field))
    {
        Console.WriteLine($"  Field: {openResult.Field}");
    }
    
    if (!string.IsNullOrEmpty(openResult.Value))
    {
        Console.WriteLine($"  Value: {openResult.Value}");
    }
    
    if (openResult.Line > 0)
    {
        Console.WriteLine($"  Location: Line {openResult.Line}, Column {openResult.Column}");
    }
    
    // Common YAML parsing errors
    switch (openResult.ResultCode)
    {
        case unchecked((int)0x80070002): // ERROR_FILE_NOT_FOUND
            Console.WriteLine("Configuration file not found");
            break;
            
        case unchecked((int)0x8007007B): // ERROR_INVALID_NAME
            Console.WriteLine("Invalid YAML syntax");
            break;
    }
    
    return;
}

var configSet = openResult.Set;

Apply Configuration Errors

var applyResult = await processor.ApplySetAsync(
    configSet,
    ApplyConfigurationSetFlags.None
);

if (applyResult.ResultCode != 0)
{
    Console.WriteLine($"Configuration apply failed: 0x{applyResult.ResultCode:X8}");
}

foreach (var unitResult in applyResult.UnitResults)
{
    var unit = unitResult.Unit;
    
    if (unitResult.State == ConfigurationUnitState.Completed)
    {
        var result = unitResult.ResultInformation;
        
        if (result.ResultCode != 0)
        {
            Console.WriteLine($"\nUnit failed: {unit.Type}");
            Console.WriteLine($"  Identifier: {unit.Identifier}");
            Console.WriteLine($"  HRESULT: 0x{result.ResultCode:X8}");
            Console.WriteLine($"  Description: {result.Description}");
            Console.WriteLine($"  Details: {result.Details}");
            Console.WriteLine($"  Source: {result.ResultSource}");
            
            switch (result.ResultSource)
            {
                case ConfigurationUnitResultSource.Internal:
                    Console.WriteLine("  Internal configuration system error");
                    break;
                    
                case ConfigurationUnitResultSource.ConfigurationSet:
                    Console.WriteLine("  Configuration set is ill-formed");
                    break;
                    
                case ConfigurationUnitResultSource.UnitProcessing:
                    Console.WriteLine("  DSC resource processing error");
                    break;
                    
                case ConfigurationUnitResultSource.SystemState:
                    Console.WriteLine("  System state error");
                    break;
                    
                case ConfigurationUnitResultSource.Precondition:
                    Console.WriteLine("  Dependency failed");
                    break;
            }
        }
    }
    else if (unitResult.State == ConfigurationUnitState.Skipped)
    {
        Console.WriteLine($"\nUnit skipped: {unit.Type}");
        Console.WriteLine($"  Reason: {unitResult.ResultInformation.Description}");
    }
}

Test Configuration Errors

var testResult = await processor.TestSetAsync(configSet);

foreach (var unitResult in testResult.UnitResults)
{
    var unit = unitResult.Unit;
    var result = unitResult.ResultInformation;
    
    switch (unitResult.TestResult)
    {
        case ConfigurationTestResult.Positive:
            Console.WriteLine($"{unit.Type}: In desired state");
            break;
            
        case ConfigurationTestResult.Negative:
            Console.WriteLine($"{unit.Type}: NOT in desired state");
            break;
            
        case ConfigurationTestResult.Failed:
            Console.WriteLine($"{unit.Type}: Test FAILED");
            Console.WriteLine($"  Error: {result.Description}");
            Console.WriteLine($"  HRESULT: 0x{result.ResultCode:X8}");
            break;
            
        case ConfigurationTestResult.NotRun:
            Console.WriteLine($"{unit.Type}: Test not run");
            if (result.ResultCode != 0)
            {
                Console.WriteLine($"  Reason: {result.Description}");
            }
            break;
    }
}

Common HRESULT Codes

HRESULTNameDescription
0x00000000S_OKSuccess
0x80070002ERROR_FILE_NOT_FOUNDFile not found
0x80070005E_ACCESSDENIEDAccess denied
0x8007007BERROR_INVALID_NAMEInvalid syntax or name
0x80070057E_INVALIDARGInvalid argument
0x80070490ERROR_NOT_FOUNDElement not found
0x80070643ERROR_INSTALL_FAILUREInstallation failed
0x80070BC9ERROR_SUCCESS_REBOOT_REQUIREDReboot required
0x80072EFDWININET_E_CANNOT_CONNECTCannot connect to server
0x80072EE7ERROR_INTERNET_NAME_NOT_RESOLVEDDNS resolution failed
0x80131500COR_E_EXCEPTIONGeneral .NET exception

Best Practices

1. Always Check Status Codes

// Good
var result = await manager.InstallPackageAsync(package, options);
if (result.Status != InstallResultStatus.Ok)
{
    HandleInstallError(result);
    return;
}

// Bad - assuming success
var result = await manager.InstallPackageAsync(package, options);
// Continue without checking

2. Provide User-Friendly Messages

string GetUserFriendlyMessage(InstallResult result)
{
    return result.Status switch
    {
        InstallResultStatus.Ok => "Installation completed successfully",
        InstallResultStatus.DownloadError => "Failed to download installer. Check your internet connection.",
        InstallResultStatus.InstallError => $"Installation failed. Error code: {result.InstallerErrorCode:X}",
        InstallResultStatus.BlockedByPolicy => "Installation blocked by your organization's policy",
        InstallResultStatus.NoApplicableInstallers => "This package is not compatible with your system",
        InstallResultStatus.PackageAgreementsNotAccepted => "You must accept the package license agreement",
        _ => $"Installation failed with error: {result.Status}"
    };
}

3. Log Detailed Errors

void LogError(InstallResult result, string packageId)
{
    _logger.LogError(
        "Package installation failed. " +
        "PackageId={PackageId}, " +
        "Status={Status}, " +
        "ExtendedError=0x{ExtendedError:X8}, " +
        "InstallerError=0x{InstallerError:X}, " +
        "CorrelationData={CorrelationData}",
        packageId,
        result.Status,
        result.ExtendedErrorCode,
        result.InstallerErrorCode,
        result.CorrelationData
    );
}

4. Handle Transient Errors

async Task<InstallResult> InstallWithRetryAsync(
    CatalogPackage package, 
    InstallOptions options,
    int maxRetries = 3)
{
    for (int i = 0; i < maxRetries; i++)
    {
        var result = await _manager.InstallPackageAsync(package, options);
        
        if (result.Status == InstallResultStatus.Ok)
        {
            return result;
        }
        
        // Retry on transient errors
        if (result.Status == InstallResultStatus.DownloadError)
        {
            Console.WriteLine($"Download failed. Retry {i + 1}/{maxRetries}...");
            await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, i)));
            continue;
        }
        
        // Don't retry permanent errors
        return result;
    }
    
    throw new Exception("Max retries exceeded");
}

5. Handle Diagnostics

processor.MinimumLevel = DiagnosticLevel.Warning;

processor.Diagnostics += (sender, diagnostics) =>
{
    var logLevel = diagnostics.Level switch
    {
        DiagnosticLevel.Verbose => LogLevel.Trace,
        DiagnosticLevel.Informational => LogLevel.Information,
        DiagnosticLevel.Warning => LogLevel.Warning,
        DiagnosticLevel.Error => LogLevel.Error,
        DiagnosticLevel.Critical => LogLevel.Critical,
        _ => LogLevel.Debug
    };
    
    _logger.Log(logLevel, diagnostics.Message);
};

Build docs developers (and LLMs) love