From 299ec71d2c08153fd9a8d5eea84551c94f2aaa96 Mon Sep 17 00:00:00 2001 From: Jordan Stephens Date: Wed, 21 Jan 2026 10:26:14 -0800 Subject: [PATCH 1/5] avoid ignoring missing stack error --- src/pkg/session/session.go | 5 +++++ src/pkg/session/session_test.go | 19 ++++++++++++++++++- src/pkg/stacks/manager.go | 10 +++++++++- src/pkg/stacks/manager_test.go | 2 +- 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/pkg/session/session.go b/src/pkg/session/session.go index c7a85813a..9011ca5e1 100644 --- a/src/pkg/session/session.go +++ b/src/pkg/session/session.go @@ -2,6 +2,7 @@ package session import ( "context" + "errors" "fmt" "os" @@ -78,6 +79,10 @@ func (sl *SessionLoader) loadStack(ctx context.Context) (*stacks.Parameters, str } stack, whence, err := sl.sm.GetStack(ctx, sl.opts.GetStackOpts) if err != nil { + var notExistErr *stacks.ErrNotExist + if errors.As(err, ¬ExistErr) { + return nil, "", err + } if sl.opts.ProviderID != "" { whence = "--provider flag" } diff --git a/src/pkg/session/session_test.go b/src/pkg/session/session_test.go index 566a63e9e..ceb4ec3c9 100644 --- a/src/pkg/session/session_test.go +++ b/src/pkg/session/session_test.go @@ -94,6 +94,17 @@ func TestLoadSession(t *testing.T) { Name: "beta", }, }, + { + name: "specified non-existing stack", + options: SessionLoaderOptions{ + GetStackOpts: stacks.GetStackOpts{ + Stack: "missingstack", + }, + }, + + expectedError: "stack \"missingstack\" does not exist", + expectedEnv: map[string]string{}, + }, { name: "specified existing stack", options: SessionLoaderOptions{ @@ -151,7 +162,13 @@ func TestLoadSession(t *testing.T) { sm := &mockStacksManager{} if tt.existingStack == nil { - sm.On("GetStack", ctx, mock.Anything).Maybe().Return(nil, "", errors.New("stack not found")) + if tt.options.GetStackOpts.Stack != "" { + // For specified non-existing stack, return ErrNotExist + sm.On("GetStack", ctx, mock.Anything).Maybe().Return(nil, "", &stacks.ErrNotExist{StackName: tt.options.GetStackOpts.Stack}) + } else { + // For empty stack (should fall back to beta), return a general error that's not ErrNotExist + sm.On("GetStack", ctx, mock.Anything).Maybe().Return(nil, "", errors.New("no default stack set for project")) + } } else { sm.On("GetStack", ctx, mock.Anything).Maybe().Return(tt.existingStack, "local", nil) } diff --git a/src/pkg/stacks/manager.go b/src/pkg/stacks/manager.go index 34423d79a..61a109f4c 100644 --- a/src/pkg/stacks/manager.go +++ b/src/pkg/stacks/manager.go @@ -203,6 +203,14 @@ func (sl *manager) GetStack(ctx context.Context, opts GetStackOpts) (*Parameters return sl.getDefaultStack(ctx) } +type ErrNotExist struct { + StackName string +} + +func (e *ErrNotExist) Error() string { + return fmt.Sprintf("stack %q does not exist", e.StackName) +} + func (sm *manager) getSpecifiedStack(ctx context.Context, name string) (*Parameters, string, error) { whence := "--stack flag" _, envSet := os.LookupEnv("DEFANG_STACK") @@ -219,7 +227,7 @@ func (sm *manager) getSpecifiedStack(ctx context.Context, name string) (*Paramet // the stack file does not exist locally; try loading remotely stack, err = sm.GetRemote(ctx, name) if err != nil { - return nil, "", fmt.Errorf("failed to find stack file or previously deployed stack: %w", err) + return nil, "", &ErrNotExist{StackName: name} } // persist the remote stack file to the local target directory stackFilename, err := sm.Create(*stack) diff --git a/src/pkg/stacks/manager_test.go b/src/pkg/stacks/manager_test.go index 120de4f81..66bcd57bc 100644 --- a/src/pkg/stacks/manager_test.go +++ b/src/pkg/stacks/manager_test.go @@ -666,7 +666,7 @@ func TestGetStack(t *testing.T) { options: GetStackOpts{ Stack: "missingstack", }, - expectedError: "unable to find stack", + expectedError: "stack \"missingstack\" does not exist", expectedEnv: map[string]string{}, }, { From 717c2a8378f225939e18e33e15dc0aba59cb2771 Mon Sep 17 00:00:00 2001 From: Jordan Stephens Date: Wed, 21 Jan 2026 10:44:11 -0800 Subject: [PATCH 2/5] improve error message --- src/pkg/stacks/manager.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pkg/stacks/manager.go b/src/pkg/stacks/manager.go index 61a109f4c..81b4fd2cb 100644 --- a/src/pkg/stacks/manager.go +++ b/src/pkg/stacks/manager.go @@ -265,7 +265,7 @@ func (sm *manager) getDefaultStack(ctx context.Context) (*Parameters, string, er if connect.CodeOf(err) != connect.CodeNotFound { return nil, "", err } - term.Debugf("No default stack set for project %q; using default", sm.projectName) + term.Debugf("No default stack set for project %q; using fallback", sm.projectName) return nil, "", errors.New("no default stack set for project") } From 0f0ef11838d0fb928b6ed059516eed2344b57dbd Mon Sep 17 00:00:00 2001 From: Jordan Stephens Date: Wed, 21 Jan 2026 11:27:48 -0800 Subject: [PATCH 3/5] default provider to Defang if set to auto --- src/pkg/session/session.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/pkg/session/session.go b/src/pkg/session/session.go index 9011ca5e1..09640120d 100644 --- a/src/pkg/session/session.go +++ b/src/pkg/session/session.go @@ -93,6 +93,9 @@ func (sl *SessionLoader) loadStack(ctx context.Context) (*stacks.Parameters, str if whence == "" { whence = "fallback stack" } + if sl.opts.ProviderID == client.ProviderAuto { + sl.opts.ProviderID = client.ProviderDefang + } return &stacks.Parameters{ Name: stacks.DefaultBeta, Provider: sl.opts.ProviderID, From 142bf748cdd4ee90e4719d37d77005866570876b Mon Sep 17 00:00:00 2001 From: Jordan Stephens Date: Wed, 21 Jan 2026 11:29:56 -0800 Subject: [PATCH 4/5] avoiding returning ErrNotExist for failure to List --- src/pkg/stacks/manager.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pkg/stacks/manager.go b/src/pkg/stacks/manager.go index 81b4fd2cb..9353b18bd 100644 --- a/src/pkg/stacks/manager.go +++ b/src/pkg/stacks/manager.go @@ -173,7 +173,7 @@ func (sm *manager) GetRemote(ctx context.Context, name string) (*Parameters, err } } if remoteStack == nil { - return nil, fmt.Errorf("unable to find stack %q", name) + return nil, &ErrNotExist{StackName: name} } return &remoteStack.Parameters, nil @@ -227,7 +227,7 @@ func (sm *manager) getSpecifiedStack(ctx context.Context, name string) (*Paramet // the stack file does not exist locally; try loading remotely stack, err = sm.GetRemote(ctx, name) if err != nil { - return nil, "", &ErrNotExist{StackName: name} + return nil, "", err } // persist the remote stack file to the local target directory stackFilename, err := sm.Create(*stack) From 8bd6d105f164070c30cc2f749ea5df569e8470fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lio=E6=9D=8E=E6=AD=90?= Date: Wed, 21 Jan 2026 12:08:53 -0800 Subject: [PATCH 5/5] Update error message for Load() failure case --- src/pkg/stacks/manager_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pkg/stacks/manager_test.go b/src/pkg/stacks/manager_test.go index 66bcd57bc..fef86a1d4 100644 --- a/src/pkg/stacks/manager_test.go +++ b/src/pkg/stacks/manager_test.go @@ -614,7 +614,7 @@ GOOGLE_REGION=us-central1 // Load should fail _, err = manager.Load(t.Context(), "teststack") require.Error(t, err, "Load() should fail when target directory is empty") - require.Contains(t, err.Error(), "unable to find stack \"teststack\"", "Expected specific error message about operation not allowed") + require.Contains(t, err.Error(), "stack \"teststack\" does not exist", "Expected specific error message about operation not allowed") } func TestManager_RemoteOperationsWorkRegardlessOfDirectory(t *testing.T) {