From cc6d51cb19fd3bd7a77aa7d950f224d9c857859a Mon Sep 17 00:00:00 2001 From: rvasikarla Date: Sun, 5 Apr 2026 17:15:49 -0500 Subject: [PATCH 1/2] fix: noWatch sync no longer prevents SSH injection When a sync config has noWatch: true, the sync goroutine completes after initial sync and defer-cancels its context. This triggers the RestartOnError handler which calls parent.Kill(nil), putting the tomb in a dying state. Since SSH starts after sync completes (it waits on <-syncDone), the killed tomb prevents SSH from starting. Fix: set RestartOnError to false when NoWatch is true. A one-shot sync has no need for restart-on-error handling, and this prevents the handler from killing the parent tomb on context cancellation. Fixes #3005 Signed-off-by: rvasikarla --- pkg/devspace/services/sync/sync.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/devspace/services/sync/sync.go b/pkg/devspace/services/sync/sync.go index e2dcb88c28..e1c740b138 100644 --- a/pkg/devspace/services/sync/sync.go +++ b/pkg/devspace/services/sync/sync.go @@ -124,7 +124,7 @@ func startSync(ctx devspacecontext.Context, name, arch string, syncConfig *lates Arch: arch, Starter: starter, - RestartOnError: true, + RestartOnError: !syncConfig.NoWatch, Verbose: ctx.Log().GetLevel() == logrus.DebugLevel, } From 65c4fa09e844523935f46f5da86a9d7383eb1c6d Mon Sep 17 00:00:00 2001 From: rvasikarla Date: Fri, 1 May 2026 15:44:06 -0500 Subject: [PATCH 2/2] fix: handle onError in non-restart path for noWatch sync Address review feedback: when RestartOnError is false (noWatch), add an else block to listen for onError and onDone channels. Previously, these channels went unlistened when noWatch was true, which could cause goroutine leaks. Signed-off-by: rvasikarla --- pkg/devspace/services/sync/controller.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/pkg/devspace/services/sync/controller.go b/pkg/devspace/services/sync/controller.go index 12ab892802..2dafc779d5 100644 --- a/pkg/devspace/services/sync/controller.go +++ b/pkg/devspace/services/sync/controller.go @@ -226,6 +226,23 @@ func (c *controller) startWithWait(ctx devspacecontext.Context, options *Options } return nil }) + } else { + parent.Go(func() error { + select { + case <-ctx.Context().Done(): + syncStop(ctx, client, options, parent) + case err := <-onError: + hook.LogExecuteHooks(ctx.WithLogger(options.SyncLog), map[string]interface{}{ + "sync_config": options.SyncConfig, + "ERROR": err, + }, hook.EventsForSingle("error:sync", options.Name).With("sync.error")...) + ctx.Log().Errorf("Sync error: %v", err) + syncStop(ctx, client, options, parent) + case <-onDone: + syncDone(ctx, options, parent) + } + return nil + }) } return nil