From 8f524b23ec08e973a49967d0e892ff6344e4e5e6 Mon Sep 17 00:00:00 2001 From: jordanstephens Date: Wed, 18 Feb 2026 11:56:55 -0800 Subject: [PATCH 1/7] return ErrInvalidComposeFile when yaml parsing fails --- src/pkg/cli/compose/loader.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/pkg/cli/compose/loader.go b/src/pkg/cli/compose/loader.go index 6f34cd6eb..6415c1e57 100644 --- a/src/pkg/cli/compose/loader.go +++ b/src/pkg/cli/compose/loader.go @@ -100,6 +100,14 @@ func (l *Loader) TargetDirectory(ctx context.Context) string { return project.WorkingDir } +type ErrInvalidComposeFile struct { + error +} + +func (e ErrInvalidComposeFile) Unwrap() error { + return e.error +} + func (l *Loader) loadProject(ctx context.Context, suppressWarn bool) (*Project, error) { if l.cached != nil { return l.cached, nil @@ -116,6 +124,10 @@ func (l *Loader) loadProject(ctx context.Context, suppressWarn bool) (*Project, return nil, types.ErrComposeFileNotFound } + if strings.HasPrefix(err.Error(), "yaml: ") { + return nil, ErrInvalidComposeFile{fmt.Errorf("failed to parse compose file: %w", err)} + } + return nil, err } From c43f6b806e8701f4b2de0accef0c34e42e4bdb7b Mon Sep 17 00:00:00 2001 From: jordanstephens Date: Wed, 18 Feb 2026 11:57:44 -0800 Subject: [PATCH 2/7] factor out load error handling and invoke it during session loading --- src/cmd/cli/command/compose.go | 18 +----------------- src/cmd/cli/command/session.go | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/cmd/cli/command/compose.go b/src/cmd/cli/command/compose.go index 51d6b2126..e74d24955 100644 --- a/src/cmd/cli/command/compose.go +++ b/src/cmd/cli/command/compose.go @@ -83,23 +83,7 @@ func makeComposeUpCmd() *cobra.Command { project, loadErr := session.Loader.LoadProject(ctx) if loadErr != nil { - if global.NonInteractive { - return loadErr - } - - term.Error("Cannot load project:", loadErr) - project, err := session.Loader.CreateProjectForDebug() - if err != nil { - return err - } - - debugger, err := debug.NewDebugger(ctx, global.Cluster, session.Stack) - if err != nil { - return err - } - return debugger.DebugComposeLoadError(ctx, debug.DebugConfig{ - Project: project, - }, loadErr) + handleInvalidComposeFileErr(ctx, loadErr) } // Check if the user has permission to use the provider diff --git a/src/cmd/cli/command/session.go b/src/cmd/cli/command/session.go index 4a724940b..388156050 100644 --- a/src/cmd/cli/command/session.go +++ b/src/cmd/cli/command/session.go @@ -11,6 +11,7 @@ import ( "github.com/AlecAivazis/survey/v2" "github.com/DefangLabs/defang/src/pkg/cli/client" "github.com/DefangLabs/defang/src/pkg/cli/compose" + "github.com/DefangLabs/defang/src/pkg/debug" "github.com/DefangLabs/defang/src/pkg/session" "github.com/DefangLabs/defang/src/pkg/stacks" "github.com/DefangLabs/defang/src/pkg/term" @@ -102,6 +103,10 @@ func newStackManagerForLoader(ctx context.Context, loader *compose.Loader) (sess } projectName, _, err := loader.LoadProjectName(ctx) if err != nil { + var invalidErr compose.ErrInvalidComposeFile + if errors.As(err, &invalidErr) { + return nil, handleInvalidComposeFileErr(ctx, err) + } term.Debugf("Could not determine project name: %v", err) } sm, err := stacks.NewManager(global.Client, targetDirectory, projectName, ec) @@ -133,3 +138,23 @@ func findTargetDirectory() (string, error) { wd = parent } } + +func handleInvalidComposeFileErr(ctx context.Context, err error) error { + if global.NonInteractive { + return err + } + + term.Error("Cannot load project:", err) + project, err := compose.NewLoader().CreateProjectForDebug() + if err != nil { + return err + } + + debugger, err := debug.NewDebugger(ctx, global.Cluster, &stacks.Parameters{}) + if err != nil { + return err + } + return debugger.DebugComposeLoadError(ctx, debug.DebugConfig{ + Project: project, + }, err) +} From eb3274c15378e92c8cd0a6428c75166c7d82cd75 Mon Sep 17 00:00:00 2001 From: jordanstephens Date: Wed, 18 Feb 2026 11:58:12 -0800 Subject: [PATCH 3/7] remove "deployment" from ai prompt since it may be debugging a load error --- src/pkg/debug/debug.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pkg/debug/debug.go b/src/pkg/debug/debug.go index 2c4549660..dac7ffa60 100644 --- a/src/pkg/debug/debug.go +++ b/src/pkg/debug/debug.go @@ -141,7 +141,7 @@ func (d *Debugger) promptAndTrackDebugSession(fn func() error, eventName string, func (d *Debugger) promptForPermission() (bool, error) { var aiDebug bool err := d.surveyor.AskOne(&survey.Confirm{ - Message: "Would you like to debug the deployment with AI?", + Message: "Would you like to debug this with the Defang AI Agent?", Help: "This will send logs and artifacts to our backend and attempt to diagnose the issue and provide a solution.", }, &aiDebug, survey.WithStdio(term.DefaultTerm.Stdio())) if err != nil { From 6b9b3ce58457d3710b9fcb11d43bdb5873b3082f Mon Sep 17 00:00:00 2001 From: jordanstephens Date: Wed, 18 Feb 2026 12:13:31 -0800 Subject: [PATCH 4/7] also handle compose load errors in compose config --- src/cmd/cli/command/compose.go | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/src/cmd/cli/command/compose.go b/src/cmd/cli/command/compose.go index e74d24955..c7cc0caed 100644 --- a/src/cmd/cli/command/compose.go +++ b/src/cmd/cli/command/compose.go @@ -23,7 +23,6 @@ import ( "github.com/DefangLabs/defang/src/pkg/stacks" "github.com/DefangLabs/defang/src/pkg/term" "github.com/DefangLabs/defang/src/pkg/timeutils" - "github.com/DefangLabs/defang/src/pkg/track" "github.com/DefangLabs/defang/src/pkg/types" defangv1 "github.com/DefangLabs/defang/src/protos/io/defang/v1" "github.com/bufbuild/connect-go" @@ -83,7 +82,7 @@ func makeComposeUpCmd() *cobra.Command { project, loadErr := session.Loader.LoadProject(ctx) if loadErr != nil { - handleInvalidComposeFileErr(ctx, loadErr) + return handleInvalidComposeFileErr(ctx, loadErr) } // Check if the user has permission to use the provider @@ -534,26 +533,7 @@ func makeComposeConfigCmd() *cobra.Command { project, loadErr := sessionx.Loader.LoadProject(ctx) if loadErr != nil { - if global.NonInteractive { - return loadErr - } - - term.Error("Cannot load project:", loadErr) - project, err := sessionx.Loader.CreateProjectForDebug() - if err != nil { - term.Warn("Failed to create project for debug:", err) - return loadErr - } - - track.Evt("Debug Prompted", P("loadErr", loadErr)) - debugger, err := debug.NewDebugger(ctx, global.Cluster, &global.Stack) - if err != nil { - term.Warn("Failed to initialize debugger:", err) - return loadErr - } - return debugger.DebugComposeLoadError(ctx, debug.DebugConfig{ - Project: project, - }, loadErr) + return handleInvalidComposeFileErr(ctx, loadErr) } _, _, err = cli.ComposeUp(ctx, global.Client, sessionx.Provider, sessionx.Stack, cli.ComposeUpParams{ From 858e56b9e23c8033515524e0008314174dc40001 Mon Sep 17 00:00:00 2001 From: jordanstephens Date: Wed, 18 Feb 2026 12:13:46 -0800 Subject: [PATCH 5/7] avoid swallowing original error --- src/cmd/cli/command/session.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/cmd/cli/command/session.go b/src/cmd/cli/command/session.go index 388156050..21188aa93 100644 --- a/src/cmd/cli/command/session.go +++ b/src/cmd/cli/command/session.go @@ -154,7 +154,11 @@ func handleInvalidComposeFileErr(ctx context.Context, err error) error { if err != nil { return err } - return debugger.DebugComposeLoadError(ctx, debug.DebugConfig{ + debugErr := debugger.DebugComposeLoadError(ctx, debug.DebugConfig{ Project: project, }, err) + if debugErr != nil { + return fmt.Errorf("failed to debug compose load error: %w; original error: %v", debugErr, err) + } + return err } From 9b7f80b181b605b696c39980a5912fc7c0ef887b Mon Sep 17 00:00:00 2001 From: jordanstephens Date: Wed, 18 Feb 2026 12:23:09 -0800 Subject: [PATCH 6/7] also catch valid yaml, but invalid compose --- src/pkg/cli/compose/loader.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/pkg/cli/compose/loader.go b/src/pkg/cli/compose/loader.go index 6415c1e57..fb5865842 100644 --- a/src/pkg/cli/compose/loader.go +++ b/src/pkg/cli/compose/loader.go @@ -128,6 +128,10 @@ func (l *Loader) loadProject(ctx context.Context, suppressWarn bool) (*Project, return nil, ErrInvalidComposeFile{fmt.Errorf("failed to parse compose file: %w", err)} } + if strings.HasPrefix(err.Error(), "validating ") { + return nil, ErrInvalidComposeFile{err} + } + return nil, err } From c392e295b7958cbd60b6abd2531e4c4980051eaf Mon Sep 17 00:00:00 2001 From: jordanstephens Date: Wed, 18 Feb 2026 12:47:08 -0800 Subject: [PATCH 7/7] refactor --- src/cmd/cli/command/session.go | 8 ++++++-- src/pkg/cli/compose/loader.go | 17 ----------------- 2 files changed, 6 insertions(+), 19 deletions(-) diff --git a/src/cmd/cli/command/session.go b/src/cmd/cli/command/session.go index 21188aa93..569032b62 100644 --- a/src/cmd/cli/command/session.go +++ b/src/cmd/cli/command/session.go @@ -16,6 +16,7 @@ import ( "github.com/DefangLabs/defang/src/pkg/stacks" "github.com/DefangLabs/defang/src/pkg/term" "github.com/DefangLabs/defang/src/pkg/track" + "github.com/DefangLabs/defang/src/pkg/types" "github.com/spf13/cobra" ) @@ -103,8 +104,7 @@ func newStackManagerForLoader(ctx context.Context, loader *compose.Loader) (sess } projectName, _, err := loader.LoadProjectName(ctx) if err != nil { - var invalidErr compose.ErrInvalidComposeFile - if errors.As(err, &invalidErr) { + if !errors.Is(err, types.ErrComposeFileNotFound) { return nil, handleInvalidComposeFileErr(ctx, err) } term.Debugf("Could not determine project name: %v", err) @@ -144,6 +144,10 @@ func handleInvalidComposeFileErr(ctx context.Context, err error) error { return err } + if !strings.HasPrefix(err.Error(), "yaml: ") && !strings.HasPrefix(err.Error(), "validating ") { + return err + } + term.Error("Cannot load project:", err) project, err := compose.NewLoader().CreateProjectForDebug() if err != nil { diff --git a/src/pkg/cli/compose/loader.go b/src/pkg/cli/compose/loader.go index fb5865842..8c110ab5d 100644 --- a/src/pkg/cli/compose/loader.go +++ b/src/pkg/cli/compose/loader.go @@ -100,14 +100,6 @@ func (l *Loader) TargetDirectory(ctx context.Context) string { return project.WorkingDir } -type ErrInvalidComposeFile struct { - error -} - -func (e ErrInvalidComposeFile) Unwrap() error { - return e.error -} - func (l *Loader) loadProject(ctx context.Context, suppressWarn bool) (*Project, error) { if l.cached != nil { return l.cached, nil @@ -123,15 +115,6 @@ func (l *Loader) loadProject(ctx context.Context, suppressWarn bool) (*Project, if errors.Is(err, errdefs.ErrNotFound) { return nil, types.ErrComposeFileNotFound } - - if strings.HasPrefix(err.Error(), "yaml: ") { - return nil, ErrInvalidComposeFile{fmt.Errorf("failed to parse compose file: %w", err)} - } - - if strings.HasPrefix(err.Error(), "validating ") { - return nil, ErrInvalidComposeFile{err} - } - return nil, err }