fix: base path resolution for ATMOS_BASE_PATH and --base-path with relative paths#2215
fix: base path resolution for ATMOS_BASE_PATH and --base-path with relative paths#2215
Conversation
When ATMOS_BASE_PATH env var, --base-path flag, or atmos_base_path provider parameter provides a simple relative path (e.g., ".terraform/modules/monorepo"), resolve it relative to CWD instead of routing through git root discovery. This restores pre-v1.202.0 behavior for explicitly set paths while preserving git root discovery for default/empty base paths. Two-pronged fix: 1. configAndStacksInfo.AtmosBasePath (provider/CLI): convert to absolute CWD-relative immediately in InitCliConfig 2. ATMOS_BASE_PATH env var (via Viper): tryResolveWithGitRoot now validates the git-root-joined path exists before using it, and falls back to CWD-relative resolution if it doesn't Also improves error messages for "failed to find import" using the error builder pattern with actionable hints and context. Fixes #2183 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Verify that the os.Stat fallback in tryResolveWithGitRoot doesn't break "run Atmos from any subdirectory" behavior. Add table-driven tests for resolveSimpleRelativeBasePath helper. Document git root discovery compatibility analysis with integration test evidence. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Dependency ReviewThe following issues were found:
License Issuesgo.mod
Scanned Files
|
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds source-aware base_path resolution: dot-prefixed values are anchored by source (runtime → CWD, config → config dir), prefer git-root for bare paths with CWD fallback, enriches glob error hints, adds tests, updates docs/PRD, and records runtime base-path source in the config schema. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant CLI as CLI / Env / Flags
participant Init as InitCliConfig
participant Resolver as resolveAbsolutePath / resolveDotPrefixPath
participant Git as GitRootDiscovery
participant FS as FileSystem / Glob
CLI->>Init: provide base_path (flag/env/config)
Init->>Resolver: classify & normalize base_path (source-aware)
alt DOT-prefixed & source=runtime
Resolver->>FS: anchor to CWD and resolve
else DOT-prefixed & source=config
Resolver->>Init: anchor to config dir and resolve
else BARE (no dot/absolute)
Init->>Git: discover git root
Git-->>Init: git-root path
Init->>FS: check git-root-joined path exists
alt exists
FS-->>Init: use git-root path
else not exists
Init->>FS: check CWD-relative path
alt exists
FS-->>Init: use CWD-relative path
else
FS-->>Init: no match -> preserve git-root path for error semantics
end
end
end
Init->>FS: run glob (GetGlobMatches)
FS-->>Init: matches or error (error enriched with hints)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
📝 Coding Plan
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@pkg/config/base_path_resolution_test.go`:
- Around line 157-188: Test TestTryResolveWithGitRoot_ExistingPathAtGitRoot only
inspects os.Stat and never invokes the path resolver; modify the test to call
the actual resolver (resolveAbsolutePath or tryResolveWithGitRoot) with the
relative "stacks" path while CWD is subDir and the git root is simulated as
tmpDir, then assert the returned absolute path equals the expected stacksDir;
ensure you capture and assert any error from resolveAbsolutePath, and restore
working directory after the test if you change it.
- Around line 207-210: The test case using a hardcoded Unix path in the test row
named "absolute path returned as-is" should be changed to compute an absolute
path at runtime to be cross-platform: replace the literal value assigned to the
test row's input with a value produced via filepath.Abs (e.g., call filepath.Abs
on a relative path or a joined path created with filepath.Join) and handle the
error if any before using it in the test, ensuring the test uses that computed
absolute path for the input field instead of the hardcoded "/usr/local/atmos".
In `@pkg/config/config.go`:
- Around line 334-351: The code currently treats all os.Stat errors the same and
returns raw errors from filepath.Abs; update the logic around gitRootJoined and
cwdJoined to distinguish "not found" vs other I/O errors by using
os.IsNotExist(err): when os.Stat(gitRootJoined) returns an error that is not
os.IsNotExist, return a wrapped/static error (use the repo's static error
pattern, e.g., fmt.Errorf("...: %w", ErrIO or similar) or existing
error-wrapping helper) instead of falling back; likewise after
filepath.Abs(path) wrap that error with the project's static error type before
returning; when os.Stat(cwdJoined) returns an error, if os.IsNotExist continue
to the final fallback, otherwise return a wrapped I/O error immediately. Ensure
you reference gitRootJoined, cwdJoined, os.Stat, and filepath.Abs in your
changes.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 1b226628-c26f-4b4f-91a1-5e2df566d2bc
📒 Files selected for processing (5)
docs/fixes/2026-03-17-failed-to-find-import-base-path-resolution.mdpkg/config/base_path_resolution_test.gopkg/config/config.gopkg/config/utils.gopkg/utils/glob_utils.go
- Distinguish os.Stat ENOENT from permission/I/O errors in tryResolveWithGitRoot using os.IsNotExist() checks - Use error builder pattern (ErrStatFile, ErrPathResolution) for non-ENOENT failures instead of silently falling back - Remove WithExitCode(2) from error builders — restores default exit code 1, fixing helmfile apply non-existent CI test - Replace hardcoded Unix path in test with filepath.Abs() - Rewrite TestTryResolveWithGitRoot_ExistingPathAtGitRoot to actually call resolveAbsolutePath instead of just checking os.Stat preconditions - Add TestTryResolveWithGitRoot_CWDFallback covering the core fix path - Add TestTryResolveWithGitRoot_NeitherExists for fallback to git root Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
@aknysh please update and reconcile our PRD. I'm curious what our thinking was at the time. https://github.com/cloudposse/atmos/blob/main/docs/prd/base-path-resolution-semantics.md |
The PRD has a gap that directly caused this bug. The PRD covers base_path values set in atmos.yaml, but it doesn't account for the different sources of base_path:
The core tension: The PRD says "foo" → search git root → config dir (line 28). This makes sense for config-file values (you'd write stacks in atmos.yaml meaning /stacks). But when a user sets What needs reconciling:
My opinion: Erik is right to flag this. The PRD formalized semantics for config-file values but didn't distinguish between sources. Our fix is consistent with the PRD's spirit (config-relative for config files, CWD-relative for user-provided |
Add FR6 (Runtime Source Resolution) formalizing that --base-path, ATMOS_BASE_PATH env var, and atmos_base_path provider parameter resolve simple relative paths relative to CWD, not git root. Document the design rationale for source-dependent resolution, add runtime test cases, implementation details, and Issue #2183 resolution. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
🧹 Nitpick comments (1)
docs/prd/base-path-resolution-semantics.md (1)
254-269: Runtime source test cases are comprehensive.These examples match the scenarios covered in the unit tests. One minor note: the code block starting at line 256 lacks a language specifier (MD040). Not blocking.
Optional: add language specifier
-``` +```text # Scenario: CWD is /repo/components/terraform/vpc, git root is /repo🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/prd/base-path-resolution-semantics.md` around lines 254 - 269, The fenced code block in the docs lacks a language specifier (MD040); update the triple-backtick fence that starts the example (the block containing "# Scenario: CWD is /repo/components/terraform/vpc, git root is /repo") to include a language tag such as "text" (e.g., change ``` to ```text) so the markdown linter stops flagging MD040 and the snippet renders with the intended plain-text formatting.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@docs/prd/base-path-resolution-semantics.md`:
- Around line 254-269: The fenced code block in the docs lacks a language
specifier (MD040); update the triple-backtick fence that starts the example (the
block containing "# Scenario: CWD is /repo/components/terraform/vpc, git root is
/repo") to include a language tag such as "text" (e.g., change ``` to ```text)
so the markdown linter stops flagging MD040 and the snippet renders with the
intended plain-text formatting.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 5ba8a4a0-b461-462a-abad-88603c36f0ea
📒 Files selected for processing (4)
docs/prd/base-path-resolution-semantics.mdpkg/config/base_path_resolution_test.gopkg/config/config.gopkg/config/utils.go
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #2215 +/- ##
==========================================
+ Coverage 76.85% 76.88% +0.02%
==========================================
Files 1001 1001
Lines 95361 95392 +31
==========================================
+ Hits 73294 73346 +52
+ Misses 17802 17782 -20
+ Partials 4265 4264 -1
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
The CWDFallback test was creating a temp dir outside the git repo, causing getGitRootOrEmpty() to return "" and skip the os.Stat fallback logic entirely. Now creates the test dir inside the repo so git root discovery works, increasing tryResolveWithGitRoot coverage from 76% to 84%. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Updated: anthropic-sdk-go v1.27.0, googleapis/gax-go v2.19.0, google.golang.org/api v0.272.0, modernc.org/sqlite v1.47.0, google.golang.org/genproto 20260316, charmbracelet/x/exp/slice 20260316. Pinned: gocloud.dev v0.41.0 and go-fsimpl v0.3.1 (gomplate/v3 incompatible with newer versions due to s3blob.URLOpener changes). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ndent semantics
Establish a unified convention where:
- Empty ("") = smart defaults (git root search)
- Dot (".", "./foo", "..", "../foo") = explicit anchor, context-dependent
- In atmos.yaml: anchor to config directory (config-file convention)
- In env var/CLI/provider: anchor to CWD (shell convention)
- Bare ("foo", "stacks") = search path, source-independent (always git root search)
- Absolute ("/path") = pass through unchanged
This eliminates the incongruence where "" and "." were treated identically or where
the same bare path value behaved differently based on source. The convention is now
unambiguous: empty is absence of opinion, dot is contextual anchor, bare is a search.
## Changes
**Core implementation:**
- Add `BasePathSource` field to `AtmosConfiguration` to track source (runtime vs config)
- Make `resolveAbsolutePath()` source-aware: dot-prefix resolves to CWD for runtime, config dir for config
- Mark source as "runtime" when base_path comes from env var, CLI flag, or provider parameter
- Remove `resolveSimpleRelativeBasePath()` — no longer needed with source-aware resolution
- Extract `resolveDotPrefixPath()` helper to reduce cyclomatic complexity
- Bare paths continue through git root search regardless of source
**Testing:**
- Add comprehensive tests proving dot-prefix is source-dependent, bare paths are not
- Update existing tests to reflect new convention (ATMOS_BASE_PATH=. now goes to CWD)
- All tests pass; no regressions
**Documentation:**
- Rewrite PRD with 4-category classification (Empty/Dot/Bare/Absolute)
- Add 18-row comprehensive examples table showing all scenarios
- Include source-awareness explanation and consistency proof
- Update fix documentation to reference source-aware resolution
Fixes #2183 (Tyler Rankin's ATMOS_BASE_PATH=.terraform/modules/monorepo scenario).
Fixes #1858 (empty base_path with ATMOS_CLI_CONFIG_PATH).
Stacked onto PR #2215 (aknysh/fix-import-not-found).
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
NOTICE (1)
1-1:⚠️ Potential issue | 🔴 CriticalNOTICE file must be regenerated to pass CI.
The pipeline is failing because the NOTICE file is out of date. Run the following command locally and commit the result:
./scripts/generate-notice.shBased on learnings, the NOTICE file is programmatically generated and should not be manually edited.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@NOTICE` at line 1, The NOTICE file is out of date and must be regenerated to satisfy CI; run the generate-notice.sh script to regenerate the NOTICE file and commit the updated NOTICE (do not manually edit it). Locate the existing NOTICE file and the generate-notice.sh script referenced in the repo, execute the script locally to produce the new NOTICE, verify changes, and commit them so the pipeline will pass.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@NOTICE`:
- Line 1: The NOTICE file is out of date and must be regenerated to satisfy CI;
run the generate-notice.sh script to regenerate the NOTICE file and commit the
updated NOTICE (do not manually edit it). Locate the existing NOTICE file and
the generate-notice.sh script referenced in the repo, execute the script locally
to produce the new NOTICE, verify changes, and commit them so the pipeline will
pass.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: d3774f85-d5b2-4f49-b5ed-2e9d78bebce0
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (2)
NOTICEgo.mod
* docs(prd): formalize base path resolution convention with source-dependent semantics
Establish a unified convention where:
- Empty ("") = smart defaults (git root search)
- Dot (".", "./foo", "..", "../foo") = explicit anchor, context-dependent
- In atmos.yaml: anchor to config directory (config-file convention)
- In env var/CLI/provider: anchor to CWD (shell convention)
- Bare ("foo", "stacks") = search path, source-independent (always git root search)
- Absolute ("/path") = pass through unchanged
This eliminates the incongruence where "" and "." were treated identically or where
the same bare path value behaved differently based on source. The convention is now
unambiguous: empty is absence of opinion, dot is contextual anchor, bare is a search.
## Changes
**Core implementation:**
- Add `BasePathSource` field to `AtmosConfiguration` to track source (runtime vs config)
- Make `resolveAbsolutePath()` source-aware: dot-prefix resolves to CWD for runtime, config dir for config
- Mark source as "runtime" when base_path comes from env var, CLI flag, or provider parameter
- Remove `resolveSimpleRelativeBasePath()` — no longer needed with source-aware resolution
- Extract `resolveDotPrefixPath()` helper to reduce cyclomatic complexity
- Bare paths continue through git root search regardless of source
**Testing:**
- Add comprehensive tests proving dot-prefix is source-dependent, bare paths are not
- Update existing tests to reflect new convention (ATMOS_BASE_PATH=. now goes to CWD)
- All tests pass; no regressions
**Documentation:**
- Rewrite PRD with 4-category classification (Empty/Dot/Bare/Absolute)
- Add 18-row comprehensive examples table showing all scenarios
- Include source-awareness explanation and consistency proof
- Update fix documentation to reference source-aware resolution
Fixes #2183 (Tyler Rankin's ATMOS_BASE_PATH=.terraform/modules/monorepo scenario).
Fixes #1858 (empty base_path with ATMOS_CLI_CONFIG_PATH).
Stacked onto PR #2215 (aknysh/fix-import-not-found).
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
* fix: update tests for source-aware base path resolution
Update CLI test cases to use correct relative paths (e.g., "../..") instead
of "." for ATMOS_BASE_PATH env var, since env vars are now "runtime" source
and "." resolves to CWD (shell convention) not config dir.
Add unit tests for source-aware resolution: dot-prefix fallback, absolute
pass-through, bare path without git root, and BasePathSource tracking.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: use real absolute path in test for Windows compatibility
Use t.TempDir() instead of constructing path from filepath.Separator,
which lacks a drive letter on Windows and isn't recognized as absolute.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
Co-authored-by: aknysh <andriy.knysh@gmail.com>
There was a problem hiding this comment.
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)
pkg/config/config.go (1)
255-283: 🛠️ Refactor suggestion | 🟠 MajorWrap the new dot-path failures with the standard sentinels.
resolveDotPrefixPath()returns rawfmt.Errorfvalues on every failure branch, so callers loseerrors.Isclassification for path-resolution failures that the newtryResolveWithGitRoot()branches now preserve. Please route these througherrUtils.ErrPathResolution/ the builder pattern as well.As per coding guidelines, "All errors must be wrapped using static errors defined in errors/errors.go, use errors.Join for combining multiple errors, use fmt.Errorf with %w for adding context, use error builder for complex errors, use errors.Is() for checking - never use dynamic errors directly."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@pkg/config/config.go` around lines 255 - 283, resolveDotPrefixPath currently returns raw fmt.Errorf errors which prevents callers and tryResolveWithGitRoot from matching path-resolution failures; update every error return in resolveDotPrefixPath to wrap the underlying error with the standard sentinel errUtils.ErrPathResolution (from errors/errors.go) using the prescribed builder/pattern (or errors.Join/%w as appropriate) so callers can use errors.Is to detect path-resolution failures—ensure each branch (runtime, config with cliConfigPath, and fallback) constructs the new error by combining context (the fmt message) with errUtils.ErrPathResolution and the original err, mirroring how tryResolveWithGitRoot produces its wrapped errors.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/fixes/2026-03-17-failed-to-find-import-base-path-resolution.md`:
- Around line 126-139: The docs describe pre-normalizing a bare ATMOS_BASE_PATH
to an absolute path in InitCliConfig but the code in pkg/config/config.go does
not implement that behavior; update InitCliConfig (after calling
processAtmosConfigs()) to check configAndStacksInfo.AtmosBasePath first, then
fallback to os.Getenv("ATMOS_BASE_PATH"), and if the chosen path is a "simple
relative" path (does not start with ".", "..", "./", or "../") convert it to an
absolute path using filepath.Abs() while leaving paths that start with "." or
".." to be resolved later by resolveAbsolutePath(); ensure you reference these
symbols (InitCliConfig, processAtmosConfigs, configAndStacksInfo.AtmosBasePath,
os.Getenv("ATMOS_BASE_PATH"), filepath.Abs, resolveAbsolutePath) so tests
expecting ATMOS_BASE_PATH="." to resolve to CWD remain correct.
In `@pkg/config/config.go`:
- Around line 250-252: The current branch always calls
tryResolveWithGitRoot(path, isExplicitRelative, cliConfigPath) for bare relative
paths which causes runtime-sourced paths to prefer the git-root copy even when
the user supplied an explicit runtime base override; update the branch handling
where source == "runtime" and path is a bare relative (e.g., in the function
that currently returns tryResolveWithGitRoot) to first detect explicit runtime
overrides (CLI flags like --base-path or env vars
ATMOS_BASE_PATH/atmos_base_path represented by cliConfigPath/related config),
and if an explicit runtime base is present prefer resolving against the CWD (use
the existing tryResolveWithCwd or equivalent resolution logic) before falling
back to tryResolveWithGitRoot; ensure you reference and use the existing
parameters path, isExplicitRelative, source and cliConfigPath so behavior only
changes for runtime-sourced, bare relative paths with an explicit runtime base.
---
Outside diff comments:
In `@pkg/config/config.go`:
- Around line 255-283: resolveDotPrefixPath currently returns raw fmt.Errorf
errors which prevents callers and tryResolveWithGitRoot from matching
path-resolution failures; update every error return in resolveDotPrefixPath to
wrap the underlying error with the standard sentinel errUtils.ErrPathResolution
(from errors/errors.go) using the prescribed builder/pattern (or errors.Join/%w
as appropriate) so callers can use errors.Is to detect path-resolution
failures—ensure each branch (runtime, config with cliConfigPath, and fallback)
constructs the new error by combining context (the fmt message) with
errUtils.ErrPathResolution and the original err, mirroring how
tryResolveWithGitRoot produces its wrapped errors.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 314624d8-4870-4216-b5c9-13ba247db74c
📒 Files selected for processing (9)
docs/fixes/2026-03-17-failed-to-find-import-base-path-resolution.mddocs/prd/base-path-resolution-semantics.mdpkg/config/base_path_resolution_test.gopkg/config/config.gopkg/config/config_test.gopkg/config/utils.gopkg/schema/schema.gotests/snapshots/TestCLICommands_describe_component_with_relative_path.stdout.goldentests/test-cases/component-path-resolution.yaml
✅ Files skipped from review due to trivial changes (1)
- tests/snapshots/TestCLICommands_describe_component_with_relative_path.stdout.golden
docs/fixes/2026-03-17-failed-to-find-import-base-path-resolution.md
Outdated
Show resolved
Hide resolved
Replace raw fmt.Errorf calls in resolveDotPrefixPath, tryResolveWithGitRoot, and tryResolveWithConfigPath with errUtils.Build(errUtils.ErrPathResolution) for consistent error classification via errors.Is(). Update fix doc to reflect source-aware resolution with BasePathSource tracking instead of the old pre-normalize approach. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract absPathOrError() helper to consolidate 7 identical filepath.Abs error builder patterns into one function. Remove dead isExplicitRelative parameter and code block from tryResolveWithGitRoot (unreachable since dot-prefixed paths are routed to resolveDotPrefixPath before reaching it). resolveDotPrefixPath: 80% → 100%, tryResolveWithConfigPath: 80% → 100%. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Restore the simple if/else pseudocode block (per review feedback) and add a comprehensive quick-reference showing resolution examples for config-file source, runtime source, and no-git-repo scenarios. Both blocks validated against the implementation in pkg/config/config.go. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
These changes were released in v1.210.1. |
what
failed to find importerror whenATMOS_BASE_PATHenv var (or--base-pathflag /atmos_base_pathprovider parameter) is set to a relative path like.terraform/modules/monorepofailed to find importerror inatmos describe affectedcaused by git root discovery interfering with configuredbase_pathfailed to find importerror messages with actionable hints and context (pattern, stacks base path)why
Since v1.202.0,
resolveAbsolutePath()routes simple relative paths through git root discovery. This breaks two scenarios:Scenario 1:
terraform-provider-utilswithATMOS_BASE_PATHenv varWhen a user sets
ATMOS_BASE_PATH=.terraform/modules/monorepoon a CI/CD worker (e.g., Spacelift), the path should resolve relative to CWD (/project/components/terraform/iam-delegated-roles/.terraform/modules/monorepo). Instead, git root discovery resolves it to/project/.terraform/modules/monorepo— a path that doesn't exist — causingfailed to find import.Scenario 2:
atmos describe affectedIn CI environments where the working directory structure differs from expectations, git root discovery can compute the stacks base path incorrectly, causing stack processing to fail with
failed to find import.Error message problem
The bare
failed to find importerror provides no context about which import failed or what path was searched, making it impossible for users to diagnose.Fix approach
Fix 1: Source-aware base path resolution
Every
base_pathvalue is classified into one of four categories:"", unset".","./foo","..","../foo""foo","foo/bar",".terraform/...""/abs/path"A
BasePathSourcefield onAtmosConfigurationtracks whether the base path came from a runtime source or config file:ATMOS_BASE_PATH, CLI flag--base-path, provider paramatmos_base_path): setBasePathSource = "runtime". Dot-prefixed paths resolve relative to CWD (shell convention).base_pathinatmos.yaml): dot-prefixed paths resolve relative to the directory containingatmos.yaml(config-file convention).resolveAbsolutePath()now accepts asourceparameter and routes dot-prefixed paths throughresolveDotPrefixPath(). ThetryResolveWithGitRoot()function addsos.Statvalidation — if the git-root-joined path doesn't exist but the CWD-relative path does, it falls back to the CWD-relative path.Fix 2: Actionable error messages
Wrap
ErrFailedToFindImportwith the error builder pattern inFindAllStackConfigsInPathsForStack,FindAllStackConfigsInPaths, andGetGlobMatches, adding hints about checkingbase_path,stacks.base_path, andATMOS_BASE_PATH. All path resolution errors useerrUtils.Build(errUtils.ErrPathResolution)for consistenterrors.Is()classification.Spacelift/provider scenario
ATMOS_BASE_PATH=./.terraform/modules/monorepo(recommended dot-slash form): classified as Dot, runtime source → resolves relative to CWD. Works correctly.ATMOS_BASE_PATH=.terraform/modules/monorepo(existing bare form): classified as Bare, goes through git root search →os.Statat git root fails → falls back to CWD. Also works correctly.Git root discovery compatibility
The "run Atmos from any subdirectory" feature (v1.202.0+) is not affected:
"stacks","foo/bar") go through the same git root search regardless of sourcebase_pathreturns git root (unchanged)base_path: "."inatmos.yaml) continue to resolve relative to the config directoryVerified by existing integration tests:
describe_component_from_nested_dir,terraform_plan_from_nested_dir,terraform_plan_with_current_directory.Backward compatibility
ATMOS_BASE_PATH=".",--base-path=./foo): now resolve relative to CWD (shell convention). Previously resolved relative to config dir. This matches user expectations — in a shell,.means "here" (CWD)base_path: "."inatmos.yaml): continue to resolve relative toatmos.yamllocation — no change"stacks",".terraform/modules/monorepo"): go through git root search regardless of source, withos.Statfallback to CWD — source-independentbase_path: continues to use git root discovery (the v1.202.0 behavior)ATMOS_GIT_ROOT_BASEPATH=false: continues to work as a full opt-out of git root discoveryreferences
docs/prd/base-path-resolution-semantics.mddocs/fixes/2026-03-17-failed-to-find-import-base-path-resolution.mdterraform-provider-utilsv1.32.0+ withATMOS_BASE_PATHenv var