itsfatduck/optimizerDuck · error · StepExecutionException

result.Error ?? Description

Error message

result.Error ?? Description

What it means

StepExecutionException thrown when the registry revert operation in RegistryRevertStep.ExecuteAsync fails. The step performs DeleteValue/Write/CreateSubKey/DeleteSubKeyTree via RegistryService; if the returned OpResult is not Ok, the step throws with the provider's error message (or a localized description fallback). This is a fail-loud revert failure: the registry state was not restored as intended.

Solutions

  1. Run the application elevated (requireAdministrator) so HKLM writes/deletes succeed.
  2. Read result.Error / ErrorDetail to identify the concrete registry failure and check permissions on Path in regedit.
  3. If RestoreKeyTree, inspect each SubStep to find which sub-step's OpResult failed.
  4. If Action was deserialized to an unknown value, check the 'Action' field in %LocalAppData%\optimizerDuck\Revert\{id}.json for typos or version drift.
  5. Re-apply the original optimization or fix the registry value manually, then delete the stale revert file.

Example fix

// before: revert fails silently-ish at revert time
// after: validate writability before attempting revert
if (!RegistryService.KeyExists(new RegistryItem(step.Path)))
    return true; // nothing to restore
await step.ExecuteAsync(shell, logger);
Defensive patterns

Strategy: try-catch

Validate before calling

// before executing
if (!step.Path.StartsWith("HKLM") && !step.Path.StartsWith("HKCU") && !Enum.IsDefined(step.Action))
    throw new InvalidOperationException("Malformed registry revert step");

Type guard

bool IsValidRegistryStep(RegistryRevertStep s) =>
    !string.IsNullOrWhiteSpace(s.Path) && Enum.IsDefined(typeof(RevertAction), s.Action);

Try / catch

try
{
    await step.ExecuteAsync(shell, logger);
}
catch (StepExecutionException ex)
{
    logger.LogError(ex, "Registry revert failed: {Detail}", ex.ErrorDetail);
    // surface to user as a failed step; revert data stays for another attempt
}

Prevention

When it happens

Trigger: ExecuteAsync on a RegistryRevertStep whose RegistryService call returns a failed OpResult — e.g. DeleteValue on a value that is access-denied, Write to an HKLM key without admin rights, DeleteSubKeyTree on a key with open handles, or RestoreKeyTree when any sub-step fails.

Common situations: Running the app without elevation against HKLM keys; antivirus or group policy blocking registry writes; the target key/value already changed by another process; corrupt or hand-edited revert JSON with an unrecognized RevertAction string (falls into the default case which always fails).

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


AI-assisted analysis of itsfatduck/optimizerDuck@36acf585ae (2026-09-13). Data as JSON: /api/errors/5ee9f3e1464dd494. Report an issue: GitHub.

Appendix: source

Thrown at optimizerDuck/Domain/Revert/Steps/RegistryRevertStep.cs:112

                : RegistryService.Write(opCall, new RegistryItem(Path, Name!, Value, Kind)),

            RevertAction.RestoreKey => RegistryService.CreateSubKey(opCall, new RegistryItem(Path)),

            RevertAction.DeleteKey => RegistryService.DeleteSubKeyTree(
                opCall,
                new RegistryItem(Path)
            ),

            RevertAction.RestoreKeyTree => await ExecuteSubStepsAsync(shell, logger)
                .ConfigureAwait(false)
                ? OpResult.Success()
                : OpResult.Fail(Description),

            _ => OpResult.Fail(Description),
        };

        if (!result.Ok)
            throw new StepExecutionException(result.Error ?? Description, result.ErrorDetail);

        // Read-back verify for the local value actions.
        VerifyRestore(opCall);

        // Cleanup empty subkeys if they were created during apply
        if (CreatedSubKeys?.Count > 0)
            RegistryService.CleanupEmptyKeys(CreatedSubKeys, opCall.Logger);

        return true;
    }

    /// <inheritdoc />
    public JObject ToData()
    {
        var obj = new JObject
        {
            [nameof(Action)] = Action.ToString(),
            [nameof(Path)] = Path,

View on GitHub (pinned to 36acf585ae)