itsfatduck/optimizerDuck · error · StepExecutionException
Registry verify failed at
Error message
Registry verify failed at {Path}: expected key to be absent, but it still exists What it means
Thrown by VerifyRestore during RevertAction.DeleteKey when the key still exists after DeleteSubKeyTree reported success. DeleteSubKeyTree only removes empty key trees; any residual value or subkey (or an open handle) leaves the key in place, so verification fails.
Solutions
- Check for values/subkeys still under the key in regedit and delete them manually, then retry.
- Re-run elevated — access-denied children can silently block tree deletion.
- Stop the process holding handles on the key (Process Explorer, 'Find Handle').
- If the tree exceeds the backup caps, delete via PowerShell Remove-Item -Recurse and remove the revert file.
Example fix
// before
if (deleteExists)
throw new StepExecutionException($"Registry verify failed at {Path}: expected key to be absent, but it still exists", null);
// after: retry the tree delete once before failing
if (deleteExists)
{
RegistryService.DeleteSubKeyTree(opCall, new RegistryItem(Path));
RegistryService.TryKeyExists(new RegistryItem(Path), out deleteExists, call.Logger);
if (deleteExists) throw new StepExecutionException($"...expected key to be absent, but it still exists", null);
} Defensive patterns
Strategy: retry
Validate before calling
// pre-check tree contents depth/size expectations
using var key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(pathAfterRoot);
int childCount = key?.GetSubKeyNames().Length ?? 0;
if (childCount > 100) logger.LogWarning("Large key tree at {Path}; deletion may exceed backup caps", path); Type guard
bool IsDeleteKeyStillPresent(StepExecutionException ex) => ex.Message.Contains("expected key to be absent, but it still exists"); Try / catch
try { await step.ExecuteAsync(shell, logger); }
catch (StepExecutionException ex) when (ex.Message.Contains("still exists"))
{
logger.LogWarning("Key still present after DeleteSubKeyTree; retrying once elevated");
await step.ExecuteAsync(shell, logger);
} Prevention
- Stop processes holding handles on the key (Process Explorer) before reverting.
- Run elevated; denied child keys can block the tree delete.
- Avoid optimizations that create very deep/large trees near the 15-depth / 5000-item caps.
When it happens
Trigger: DeleteSubKeyTree(Path) returned Ok but TryKeyExists(Path) finds the key — a subkey/value was recreated after deletion, a process holds an open handle, or the app's DeleteSubKeyTree backup limits (max depth 15 / 5000 items) skipped part of the tree.
Common situations: Deep key trees exceeding the revert-step depth/item caps; running services keeping handles on the key; another component recreating the key immediately; non-empty keys when only subkey-less trees can actually be deleted.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Registry verify failed at
- Registry verify failed at
- Registry verify failed at
- Registry verify failed at
- Registry verify failed at
AI-assisted analysis of itsfatduck/optimizerDuck@36acf585ae (2026-09-13).
Data as JSON: /api/errors/84b25bbc567f56a4.
Report an issue: GitHub.
Appendix: source
Thrown at optimizerDuck/Domain/Revert/Steps/RegistryRevertStep.cs:323
throw new StepExecutionException(
$"Registry verify failed at {Path}: expected key to exist, but it was missing",
null
);
break;
case RevertAction.DeleteKey:
if (
!RegistryService.TryKeyExists(
new RegistryItem(Path),
out var deleteExists,
call.Logger
)
)
throw new StepExecutionException(
$"Registry verify failed at {Path}: could not query the key.",
null
);
if (deleteExists)
throw new StepExecutionException(
$"Registry verify failed at {Path}: expected key to be absent, but it still exists",
null
);
break;
default:
break;
}
}
private static bool ValuesEqual(object? actual, object? expected, RegistryValueKind kind) =>
RegistryValues.Equal(actual, expected, kind);
private async Task<bool> ExecuteSubStepsAsync(ShellService shell, ILogger logger)
{
if (SubSteps == null)
return true;
foreach (var step in SubSteps)
{View on GitHub (pinned to 36acf585ae)