Skip to content

Fix panic when loading invalid Compose file#2006

Merged
lionello merged 5 commits intomainfrom
lio/fix-load-panic
Mar 27, 2026
Merged

Fix panic when loading invalid Compose file#2006
lionello merged 5 commits intomainfrom
lio/fix-load-panic

Conversation

@lionello
Copy link
Copy Markdown
Member

@lionello lionello commented Mar 26, 2026

Description

After "debug with AI"-prompt, code would continue without session and panic.

Linked Issues

Fixes #2007

Checklist

  • I have performed a self-review of my code
  • I have added appropriate tests
  • I have updated the Defang CLI docs and/or README to reflect my changes, if necessary

Summary by CodeRabbit

  • Bug Fixes

    • Improved handling and clearer errors for invalid compose/config files; stack fallback selection behavior made more reliable.
  • Refactor

    • Command loader/session configuration streamlined to a command-specific flow (no user-facing command changes).
  • Chores

    • Updated vendored modules and module replacements.
  • Tests

    • Expanded tests and added invalid-compose test data for better validation coverage.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 26, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a26b5b77-4260-413f-93db-ef9710e82b0d

📥 Commits

Reviewing files that changed from the base of the PR and between 03c1882 and eace118.

📒 Files selected for processing (1)
  • src/cmd/cli/command/session_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/cmd/cli/command/session_test.go

📝 Walkthrough

Walkthrough

Refactors CLI loader construction by introducing configureLoaderForCommand and reshaping session loader option types (nesting LoaderOptions inside SessionLoaderOptions), adjusts stack fallback resolution into GetFallbackStack, updates command handlers/tests to use the new loader flow, and updates minor build/dependency and tool registration lines.

Changes

Cohort / File(s) Summary
CLI command loader updates
src/cmd/cli/command/commands.go, src/cmd/cli/command/compose.go, src/cmd/cli/command/deployments.go, src/cmd/cli/command/estimate.go, src/cmd/cli/command/stack.go
Replaced direct configureLoader(cmd) usage with configureLoaderForCommand(cmd) which derives session.LoaderOptions from command flags and delegates to a new configureLoader(loaderOptions) helper.
Session option reshaping & loader behavior
src/cmd/cli/command/session.go, src/pkg/session/session.go
Renamed/reshaped loader option structs: introduced LoaderOptions (ProjectName, ComposeFilePaths) and redefined SessionLoaderOptions to embed LoaderOptions + stacks.GetStackOpts. Adjusted newCommandSessionWithOpts and newStackManagerForLoader error handling to tolerate missing compose files and change invalid-compose error handling paths.
Stack fallback extraction
src/pkg/stacks/manager.go
Moved legacy provider fallback logic into new GetFallbackStack(defaults Parameters) and replaced inline fallback handling in GetStack with calls to this helper.
Tests and testdata
src/cmd/cli/command/session_test.go, src/cmd/cli/command/testdata/invalid-compose/compose.yaml
Renamed and restructured tests to exercise both newStackManagerForLoader and newCommandSessionWithOpts, added invalid-compose fixture and substring-based error assertions, and managed global provider test state.
Build & dependency tweaks
pkgs/defang/cli.nix, src/go.mod, src/pkg/agent/fs.go
Updated Nix vendorHash; converted go.mod replace to a block and added gopkg.in/yaml.v3 replacement; removed explicit generic type parameters from ai.NewTool(...) calls in CollectFsTools.

Sequence Diagram(s)

sequenceDiagram
  participant CLI as "CLI Command"
  participant Loader as "Session Loader"
  participant StackMgr as "Stack Manager / stacks.GetFallbackStack"
  participant FS as "Compose Files / FS"

  CLI->>Loader: configureLoaderForCommand(cmd) -> newSessionLoaderOptionsForCommand
  Loader->>Loader: build session.LoaderOptions (ProjectName, ComposeFilePaths)
  Loader->>FS: attempt LoadProject / resolve ProjectWorkingDir
  alt compose file missing or invalid
    FS-->>Loader: return types.ErrComposeFileNotFound / validation error
    Loader->>StackMgr: call GetFallbackStack(defaults)
    StackMgr-->>Loader: return fallback params or error
  else compose ok
    FS-->>Loader: project loaded
  end
  Loader->>StackMgr: newStackManagerForLoader(loader) (may receive nil sm)
  StackMgr-->>CLI: stack manager or error
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • jordanstephens
  • KevyVo

"🐰 I hopped through options, flags in tow,
Loader nested snug where settings grow,
When compose files hide or fall apart,
Fallbacks whisper their clever art,
Code refreshed — a happy rabbit's glow!"

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'Fix panic when loading invalid Compose file' directly describes the main objective and the core issue being addressed in the changeset.
Linked Issues check ✅ Passed The PR implements comprehensive fixes for issue #2007: refactors loader configuration with configureLoaderForCommand, adds error handling for ErrComposeFileNotFound, introduces fallback stack handling, adds tests for invalid Compose files, and removes panic-causing nil pointer dereferences.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing the panic issue: Go module updates for improved YAML validation, loader/session refactoring to support error handling, stack manager fallback behavior, AI tool instantiation updates, and test coverage for invalid Compose files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch lio/fix-load-panic

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.11.4)

level=warning msg="[linters_context] running gomodguard failed: unable to read module file go.mod: current working directory must have a go.mod file: if you are not using go modules it is suggested to disable this linter"
level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies"


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/cmd/cli/command/session.go (1)

63-93: ⚠️ Potential issue | 🟡 Minor

Guard the provider-flag lookup.

Line 70 assumes the provider flag is always registered, but cmd.Flag("provider") returns nil when absent. Calling .Changed on nil causes a panic. The test at line 135-139 creates a bare cobra.Command without registering provider, and the test case with projectName: "myproject" (line 87) will trigger this path.

Suggested fix
 	if projectName != "" {
+		providerFlag := cmd.Flag("provider")
 		var maybeProvider client.ProviderID
-		if maybeProvider.Set(projectName) == nil && !cmd.Flag("provider").Changed {
+		if maybeProvider.Set(projectName) == nil && (providerFlag == nil || !providerFlag.Changed) {
 			// using -p with a provider name instead of -P
 			term.Warnf("Project name %q looks like a provider name; did you mean to use -P=%s instead of -p?", projectName, projectName)
 			doubleCheckProjectName(projectName)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/cmd/cli/command/session.go` around lines 63 - 93,
newSessionLoaderOptionsForCommand calls cmd.Flag("provider").Changed without
guarding for nil; fetch the flag once (e.g. f := cmd.Flag("provider")), compute
a safe "not changed" boolean as (f == nil || !f.Changed) and use that in the
existing condition that calls maybeProvider.Set(projectName) == nil so you don't
dereference a nil flag; update the branch in newSessionLoaderOptionsForCommand
(and keep the existing calls to maybeProvider.Set, term.Warnf and
doubleCheckProjectName) to use this guarded check.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/cmd/cli/command/session_test.go`:
- Around line 98-103: The test currently does a shallow copy with oldGlobal :=
global which doesn't protect nested state (GlobalConfig.Stack and its
Variables); instead, save the specific fields you modify (e.g., save oldProvider
:= global.Stack.Provider and if you mutate variables save a deep copy of
global.Stack.Variables or save oldVariables := append([]Type(nil),
global.Stack.Variables...) as appropriate) and restore those specific fields in
the t.Cleanup closure (restore global.Stack.Provider and restore
global.Stack.Variables) rather than restoring the top-level global variable;
update the session_test.go setup that sets global.Stack.Provider = "defang" to
use this targeted save/restore approach.

In `@src/pkg/session/session.go`:
- Around line 77-80: When sl.sm is nil the code calls
stacks.GetFallbackStack(sl.opts.Default) which currently forces the returned
stack's Name to DefaultBeta and can drop an explicit --stack value; preserve an
explicit stack name by checking sl.opts.Default (the CLI-provided stack name)
and, if non-empty, ensure the returned stack has its Name set to sl.opts.Default
(either by calling a fallback helper that accepts a name or by updating the Name
field on the result of stacks.GetFallbackStack); modify the logic around sl.sm,
stacks.GetFallbackStack, and sl.opts.Default so an explicitly provided stack
name is not overwritten.

---

Outside diff comments:
In `@src/cmd/cli/command/session.go`:
- Around line 63-93: newSessionLoaderOptionsForCommand calls
cmd.Flag("provider").Changed without guarding for nil; fetch the flag once (e.g.
f := cmd.Flag("provider")), compute a safe "not changed" boolean as (f == nil ||
!f.Changed) and use that in the existing condition that calls
maybeProvider.Set(projectName) == nil so you don't dereference a nil flag;
update the branch in newSessionLoaderOptionsForCommand (and keep the existing
calls to maybeProvider.Set, term.Warnf and doubleCheckProjectName) to use this
guarded check.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9cf79f56-93a6-4593-abef-5c9a9e29cfb6

📥 Commits

Reviewing files that changed from the base of the PR and between dc4e3f7 and 03c1882.

⛔ Files ignored due to path filters (1)
  • src/go.sum is excluded by !**/*.sum
📒 Files selected for processing (13)
  • pkgs/defang/cli.nix
  • src/cmd/cli/command/commands.go
  • src/cmd/cli/command/compose.go
  • src/cmd/cli/command/deployments.go
  • src/cmd/cli/command/estimate.go
  • src/cmd/cli/command/session.go
  • src/cmd/cli/command/session_test.go
  • src/cmd/cli/command/stack.go
  • src/cmd/cli/command/testdata/invalid-compose/compose.yaml
  • src/go.mod
  • src/pkg/agent/fs.go
  • src/pkg/session/session.go
  • src/pkg/stacks/manager.go

Comment thread src/cmd/cli/command/session_test.go Outdated
Comment thread src/pkg/session/session.go
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Comment thread src/pkg/agent/fs.go
@lionello lionello merged commit 60236ee into main Mar 27, 2026
14 checks passed
@lionello lionello deleted the lio/fix-load-panic branch March 27, 2026 01:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Panic when triggering debugger after compose syntax error

2 participants