From fc9029de97e993d80572b9ac3047391d73865ce5 Mon Sep 17 00:00:00 2001 From: Mika Kuns Date: Wed, 15 Apr 2026 15:54:36 +0200 Subject: [PATCH] fix(installer): wait for prior service registration to clear before create After `sc delete`, the service stays in "marked for deletion" state until every open handle (services.msc, Task Manager Services tab, Event Viewer, prior sc query process) is closed. The installer used to immediately call `sc create` and hit a silent hang / confusing "specified service has been marked for deletion" error. Poll `sc query` for up to 30s after delete; if the service is still registered past that, fail with actionable guidance (close the offending console or reboot). Also translate exit 1072 from `sc create` into the same human-readable hint. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../Steps/RegisterServiceStep.cs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/ClaudeDo.Installer/Steps/RegisterServiceStep.cs b/src/ClaudeDo.Installer/Steps/RegisterServiceStep.cs index ef29c15..40364e8 100644 --- a/src/ClaudeDo.Installer/Steps/RegisterServiceStep.cs +++ b/src/ClaudeDo.Installer/Steps/RegisterServiceStep.cs @@ -23,6 +23,24 @@ public sealed class RegisterServiceStep : IInstallStep progress.Report("Removing existing service registration (if any)..."); await RunSc($"delete {ServiceName}", ctx, progress, ct, ignoreErrors: true); + // Wait for the service to actually disappear from SCM. `sc delete` returns + // immediately but the service stays "marked for deletion" until every open + // handle (services.msc, Task Manager, a prior sc query process) is closed. + // Poll up to 30s — then fail with actionable guidance if it's still there. + progress.Report("Waiting for prior service registration to clear..."); + for (var i = 0; i < 30; i++) + { + ct.ThrowIfCancellationRequested(); + var (queryExit, _) = await RunSc($"query {ServiceName}", ctx, progress, ct, ignoreErrors: true); + if (queryExit != 0) break; // service no longer registered — good + if (i == 29) + return StepResult.Fail( + $"Service '{ServiceName}' is marked for deletion but hasn't cleared after 30s. " + + "Close any open Services console (services.msc), Task Manager Services tab, or " + + "Event Viewer showing the service, then retry. A reboot will also clear it."); + await Task.Delay(1000, ct); + } + // Create service var startType = ctx.AutoStart ? "auto" : "demand"; var createArgs = $"create {ServiceName} binPath= \"{workerExe}\" start= {startType}"; @@ -35,6 +53,10 @@ public sealed class RegisterServiceStep : IInstallStep progress.Report("Creating service..."); var (exitCode, output) = await RunSc(createArgs, ctx, progress, ct); + if (exitCode == 1072) + return StepResult.Fail( + $"Service '{ServiceName}' is still marked for deletion. " + + "Close services.msc / Task Manager / Event Viewer and retry, or reboot."); if (exitCode != 0) return StepResult.Fail($"sc.exe create failed (exit {exitCode}): {output}");