From 7f96f2d4ec504ce395cf553e4e0479772faa3110 Mon Sep 17 00:00:00 2001 From: Fabrizio Gomez Date: Sun, 21 Jun 2026 16:54:29 -0600 Subject: [PATCH 01/10] fix(config): tolerate missing config.json instead of hard-failing --- config/auth.go | 7 +++++++ config/load.go | 11 +++++++++-- context/context.add.go | 3 +++ context/context.delete.go | 4 ++++ context/current.go | 4 ++++ context/store.go | 3 +++ 6 files changed, 30 insertions(+), 2 deletions(-) diff --git a/config/auth.go b/config/auth.go index e74c02ee..18ce22b6 100644 --- a/config/auth.go +++ b/config/auth.go @@ -1,6 +1,7 @@ package config import ( + "errors" "fmt" "github.com/moby/moby/api/pkg/authconfig" @@ -17,6 +18,9 @@ const tokenUsername = "" // The returned map is keyed by the registry registry hostname for each image. func AuthConfigs(images ...string) (map[string]registry.AuthConfig, error) { cfg, err := Load() + if errors.Is(err, ErrConfigFileNotFound) { + return map[string]registry.AuthConfig{}, nil + } if err != nil { return nil, fmt.Errorf("load config: %w", err) } @@ -30,6 +34,9 @@ func AuthConfigs(images ...string) (map[string]registry.AuthConfig, error) { // If the config doesn't exist, it will attempt to load registry credentials using the default credential helper for the platform. func AuthConfigForHostname(hostname string) (registry.AuthConfig, error) { cfg, err := Load() + if errors.Is(err, ErrConfigFileNotFound) { + return registry.AuthConfig{}, nil + } if err != nil { return registry.AuthConfig{}, fmt.Errorf("load config: %w", err) } diff --git a/config/load.go b/config/load.go index 116155f1..90525b76 100644 --- a/config/load.go +++ b/config/load.go @@ -75,6 +75,8 @@ func fileExists(path string) bool { // Filepath returns the path to the docker cli config file, // checking if the file exists. +var ErrConfigFileNotFound = errors.New("config file not found") + func Filepath() (string, error) { dir, err := Dir() if err != nil { @@ -83,7 +85,7 @@ func Filepath() (string, error) { configFilePath := filepath.Join(dir, FileName) if !fileExists(configFilePath) { - return "", fmt.Errorf("config file does not exist (%s)", configFilePath) + return "", errors.Join(fmt.Errorf("config file does not exist (%s)", configFilePath), ErrConfigFileNotFound) } return configFilePath, nil @@ -93,6 +95,8 @@ func Filepath() (string, error) { // 1. the DOCKER_AUTH_CONFIG environment variable, unmarshalling it into a Config // 2. the DOCKER_CONFIG environment variable, as the path to the config file // 3. else it will load the default config file, which is ~/.docker/config.json +var ErrConfigPathNotExists = errors.New("cfg path doesn;t exist") + func Load() (Config, error) { if env := os.Getenv("DOCKER_AUTH_CONFIG"); env != "" { var cfg Config @@ -105,10 +109,13 @@ func Load() (Config, error) { var cfg Config p, err := Filepath() if err != nil { - return cfg, fmt.Errorf("config path: %w", err) + return cfg, errors.Join(fmt.Errorf("config path: %w", err), ErrConfigPathNotExists) } cfg, err = loadFromFilepath(p) + if errors.Is(err, os.ErrNotExist) { + return cfg, nil + } if err != nil { return cfg, fmt.Errorf("load config: %w", err) } diff --git a/context/context.add.go b/context/context.add.go index ecdb232b..c3528e5a 100644 --- a/context/context.add.go +++ b/context/context.add.go @@ -64,6 +64,9 @@ func New(name string, opts ...CreateContextOption) (*Context, error) { // set the context as the current context if the option is set if defaultOptions.current { cfg, err := config.Load() + if errors.Is(err, config.ErrConfigFileNotFound) { + return ctx, nil + } if err != nil { return nil, fmt.Errorf("load config: %w", err) } diff --git a/context/context.delete.go b/context/context.delete.go index 062e7c95..36d37e13 100644 --- a/context/context.delete.go +++ b/context/context.delete.go @@ -30,6 +30,10 @@ func (ctx *Context) Delete() error { if ctx.isCurrent { // reset the current context to the default context cfg, err := config.Load() + if errors.Is(err, config.ErrConfigFileNotFound) { + return nil + } + if err != nil { return fmt.Errorf("load config: %w", err) } diff --git a/context/current.go b/context/current.go index 7e86deed..dbab38cd 100644 --- a/context/current.go +++ b/context/current.go @@ -1,6 +1,7 @@ package context import ( + "errors" "fmt" "net/url" "os" @@ -25,6 +26,9 @@ func Current() (string, error) { if os.IsNotExist(err) { return DefaultContextName, nil } + if errors.Is(err, config.ErrConfigFileNotFound) { + return DefaultContextName, nil + } return "", fmt.Errorf("load docker config: %w", err) } diff --git a/context/store.go b/context/store.go index 8acaf1e1..25d8c281 100644 --- a/context/store.go +++ b/context/store.go @@ -140,6 +140,9 @@ func (s *store) inspect(ctxName string) (Context, error) { } cfg, err := config.Load() + if errors.Is(err, config.ErrConfigFileNotFound) { + return *ctx, nil + } if err != nil { return Context{}, fmt.Errorf("load config: %w", err) } From f981c064e73845b8c14eef1723db0ea3b2e80e49 Mon Sep 17 00:00:00 2001 From: Fabrizio Gomez Date: Sun, 21 Jun 2026 16:55:34 -0600 Subject: [PATCH 02/10] fix(config): drop unused ErrConfigPathNotExists sentinel --- config/load.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/config/load.go b/config/load.go index 90525b76..ad1841cf 100644 --- a/config/load.go +++ b/config/load.go @@ -95,8 +95,6 @@ func Filepath() (string, error) { // 1. the DOCKER_AUTH_CONFIG environment variable, unmarshalling it into a Config // 2. the DOCKER_CONFIG environment variable, as the path to the config file // 3. else it will load the default config file, which is ~/.docker/config.json -var ErrConfigPathNotExists = errors.New("cfg path doesn;t exist") - func Load() (Config, error) { if env := os.Getenv("DOCKER_AUTH_CONFIG"); env != "" { var cfg Config @@ -109,7 +107,7 @@ func Load() (Config, error) { var cfg Config p, err := Filepath() if err != nil { - return cfg, errors.Join(fmt.Errorf("config path: %w", err), ErrConfigPathNotExists) + return cfg, fmt.Errorf("config path: %w", err) } cfg, err = loadFromFilepath(p) From 1dc65b6924c8d7d345cd30a4b0fb960883b90cfe Mon Sep 17 00:00:00 2001 From: Fabrizio Gomez Date: Mon, 22 Jun 2026 01:04:34 -0600 Subject: [PATCH 03/10] Move sentinel error to errors.go --- config/errors.go | 7 +++++++ config/load.go | 2 -- 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 config/errors.go diff --git a/config/errors.go b/config/errors.go new file mode 100644 index 00000000..b936d193 --- /dev/null +++ b/config/errors.go @@ -0,0 +1,7 @@ +package config + +import "errors" + +// ErrConfigFileNotFound is used as a sentinel error to distinguish when a docker config file is not present, +// so that cases without a config file work, but cases with an invalid config file still fail +var ErrConfigFileNotFound = errors.New("config file not found") diff --git a/config/load.go b/config/load.go index ad1841cf..33262e00 100644 --- a/config/load.go +++ b/config/load.go @@ -75,8 +75,6 @@ func fileExists(path string) bool { // Filepath returns the path to the docker cli config file, // checking if the file exists. -var ErrConfigFileNotFound = errors.New("config file not found") - func Filepath() (string, error) { dir, err := Dir() if err != nil { From 8c25a8344e5e63eb06c1d36d8b31207b14c17a4b Mon Sep 17 00:00:00 2001 From: Fabrizio Gomez Date: Mon, 22 Jun 2026 01:10:19 -0600 Subject: [PATCH 04/10] fix(context): The context encoded name is pre-calculated before returning, even when the config file is not found --- context/store.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/context/store.go b/context/store.go index 25d8c281..98560020 100644 --- a/context/store.go +++ b/context/store.go @@ -139,6 +139,8 @@ func (s *store) inspect(ctxName string) (Context, error) { return Context{}, ErrDockerHostNotSet } + ctx.encodedName = digest.FromString(ctx.Name).Encoded() + cfg, err := config.Load() if errors.Is(err, config.ErrConfigFileNotFound) { return *ctx, nil @@ -148,8 +150,6 @@ func (s *store) inspect(ctxName string) (Context, error) { } ctx.isCurrent = cfg.CurrentContext == ctx.Name - ctx.encodedName = digest.FromString(ctx.Name).Encoded() - return *ctx, nil } } From ba5cd4610692eb71e01bba0134df031101aecb98 Mon Sep 17 00:00:00 2001 From: Fabrizio Gomez Date: Mon, 22 Jun 2026 01:16:32 -0600 Subject: [PATCH 05/10] fix(config): fall back to credential helper when config is missing --- config/auth.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/config/auth.go b/config/auth.go index 18ce22b6..12fed357 100644 --- a/config/auth.go +++ b/config/auth.go @@ -19,7 +19,8 @@ const tokenUsername = "" func AuthConfigs(images ...string) (map[string]registry.AuthConfig, error) { cfg, err := Load() if errors.Is(err, ErrConfigFileNotFound) { - return map[string]registry.AuthConfig{}, nil + cfg = Config{} + err = nil } if err != nil { return nil, fmt.Errorf("load config: %w", err) @@ -35,7 +36,8 @@ func AuthConfigs(images ...string) (map[string]registry.AuthConfig, error) { func AuthConfigForHostname(hostname string) (registry.AuthConfig, error) { cfg, err := Load() if errors.Is(err, ErrConfigFileNotFound) { - return registry.AuthConfig{}, nil + cfg = Config{} + err = nil } if err != nil { return registry.AuthConfig{}, fmt.Errorf("load config: %w", err) From 72f1064d6e11ba1754d39dd7a91595570b62cb37 Mon Sep 17 00:00:00 2001 From: Fabrizio Gomez Date: Mon, 22 Jun 2026 01:26:36 -0600 Subject: [PATCH 06/10] test(config,context): cover ErrConfigFileNotFound code paths --- config/auth_missing_config_test.go | 79 +++++++++++++++++++++ context/missing_config_test.go | 106 +++++++++++++++++++++++++++++ 2 files changed, 185 insertions(+) create mode 100644 config/auth_missing_config_test.go create mode 100644 context/missing_config_test.go diff --git a/config/auth_missing_config_test.go b/config/auth_missing_config_test.go new file mode 100644 index 00000000..faeea013 --- /dev/null +++ b/config/auth_missing_config_test.go @@ -0,0 +1,79 @@ +package config + +import ( + "errors" + "os/exec" + "testing" + + "github.com/stretchr/testify/require" +) + +// setupConfigDirWithoutFile creates a temporary directory and sets DOCKER_CONFIG +// to point to it, but does NOT create a config.json file. This exercises the +// ErrConfigFileNotFound code path in Load/Filepath. +func setupConfigDirWithoutFile(t *testing.T) { + t.Helper() + t.Setenv(EnvOverrideDir, t.TempDir()) +} + +func TestAuthConfigs_ConfigNotFound(t *testing.T) { + setupConfigDirWithoutFile(t) + mockExecCommand(t) + + authConfigs, err := AuthConfigs("some.io/repo/image:tag") + require.NoError(t, err) + require.Contains(t, authConfigs, "some.io") + require.Empty(t, authConfigs["some.io"].Username) + require.Empty(t, authConfigs["some.io"].Password) +} + +func TestAuthConfigs_ConfigNotFound_FallsBackToCredentialHelper(t *testing.T) { + setupConfigDirWithoutFile(t) + + execLookPath = func(string) (string, error) { + return "", errors.New("helper unreachable") + } + t.Cleanup(func() { execLookPath = exec.LookPath }) + + _, err := AuthConfigs("some.io/repo/image:tag") + require.Error(t, err) + require.ErrorContains(t, err, "helper unreachable") +} + +func TestAuthConfigForHostname_ConfigNotFound(t *testing.T) { + setupConfigDirWithoutFile(t) + mockExecCommand(t) + + creds, err := AuthConfigForHostname("some.io") + require.NoError(t, err) + require.Empty(t, creds.Username) + require.Empty(t, creds.Password) +} + +func TestAuthConfigForHostname_ConfigNotFound_FallsBackToCredentialHelper(t *testing.T) { + setupConfigDirWithoutFile(t) + + execLookPath = func(string) (string, error) { + return "", errors.New("helper unreachable") + } + t.Cleanup(func() { execLookPath = exec.LookPath }) + + _, err := AuthConfigForHostname("some.io") + require.Error(t, err) + require.ErrorContains(t, err, "helper unreachable") +} + +func TestLoad_ConfigNotFound_ReturnsSentinel(t *testing.T) { + setupConfigDirWithoutFile(t) + + _, err := Load() + require.ErrorIs(t, err, ErrConfigFileNotFound) +} + +func TestFilepath_ConfigNotFound_ReturnsSentinel(t *testing.T) { + setupConfigDirWithoutFile(t) + + _, err := Filepath() + require.ErrorIs(t, err, ErrConfigFileNotFound) + require.Contains(t, err.Error(), "config file does not exist") +} diff --git a/context/missing_config_test.go b/context/missing_config_test.go new file mode 100644 index 00000000..e3c3add8 --- /dev/null +++ b/context/missing_config_test.go @@ -0,0 +1,106 @@ +package context + +import ( + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/docker/go-sdk/config" +) + +// setupDockerDirWithoutConfigFile creates a ~/.docker directory in a temp home +// so that config.Dir() succeeds, but does NOT create config.json, so that +// config.Load() returns ErrConfigFileNotFound. +func setupDockerDirWithoutConfigFile(tb testing.TB) { + tb.Helper() + tmpDir := tb.TempDir() + tb.Setenv("HOME", tmpDir) + tb.Setenv("USERPROFILE", tmpDir) // Windows support + require.NoError(tb, os.MkdirAll(filepath.Join(tmpDir, ".docker"), 0o755)) +} + +// removeConfigFile deletes the config.json from the current DOCKER_CONFIG dir. +func removeConfigFile(tb testing.TB) { + tb.Helper() + dir, err := config.Dir() + require.NoError(tb, err) + require.NoError(tb, os.Remove(filepath.Join(dir, config.FileName))) +} + +func TestCurrent_ConfigNotFound(t *testing.T) { + setupDockerDirWithoutConfigFile(t) + + current, err := Current() + require.NoError(t, err) + require.Equal(t, DefaultContextName, current) +} + +func TestInspect_ConfigNotFound(t *testing.T) { + SetupTestDockerContexts(t, 1, 3) // creates config.json with currentContext=context1 + removeConfigFile(t) // simulate a fresh install without config.json + + ctx, err := Inspect("context1") + require.NoError(t, err) + require.Equal(t, "context1", ctx.Name) + require.Equal(t, "tcp://127.0.0.1:1", ctx.Endpoints["docker"].Host) + + require.NotEmpty(t, ctx.encodedName, "encodedName should be set even when config is missing") + require.False(t, ctx.isCurrent, "isCurrent should be false when config file is missing") +} + +func TestStore_Inspect_ConfigNotFound(t *testing.T) { + SetupTestDockerContexts(t, 1, 3) + removeConfigFile(t) + + metaDir, err := metaRoot() + require.NoError(t, err) + s := &store{root: metaDir} + + ctx, err := s.inspect("context1") + require.NoError(t, err) + require.Equal(t, "context1", ctx.Name) + require.NotEmpty(t, ctx.encodedName) + require.False(t, ctx.isCurrent) +} + +func TestNew_AsCurrent_ConfigNotFound(t *testing.T) { + setupDockerDirWithoutConfigFile(t) + + ctx, err := New("newctx", + WithHost("tcp://127.0.0.1:9999"), + AsCurrent(), + ) + require.NoError(t, err) + defer func() { require.NoError(t, ctx.Delete()) }() + + require.Equal(t, "newctx", ctx.Name) + require.False(t, ctx.isCurrent, "isCurrent should be false when config file is missing") + + list, err := List() + require.NoError(t, err) + require.Contains(t, list, "newctx") + + current, err := Current() + require.NoError(t, err) + require.NotEqual(t, "newctx", current, "current should not be the new context without a config file") +} + +func TestDelete_CurrentContext_ConfigNotFound(t *testing.T) { + SetupTestDockerContexts(t, 1, 3) // creates config.json + contexts + + ctx, err := New("deleteme", + WithHost("tcp://127.0.0.1:9999"), + AsCurrent(), + ) + require.NoError(t, err) + require.True(t, ctx.isCurrent, "new context should be current") + + removeConfigFile(t) + + require.NoError(t, ctx.Delete(), "delete should not fail when config file is missing") + + _, err = Inspect("deleteme") + require.ErrorIs(t, err, ErrDockerContextNotFound) +} From a6f166db742779f0d0d5567e66cb9c990c401e65 Mon Sep 17 00:00:00 2001 From: Fabrizio Gomez Date: Mon, 22 Jun 2026 20:38:21 -0600 Subject: [PATCH 07/10] fix(config): Adress the scenarios where the config dir may be missing and return the sentinel error on those too --- config/load.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/config/load.go b/config/load.go index 33262e00..5f623bc0 100644 --- a/config/load.go +++ b/config/load.go @@ -47,19 +47,19 @@ func Dir() (string, error) { dir := os.Getenv(EnvOverrideDir) if dir != "" { if !fileExists(dir) { - return "", fmt.Errorf("file does not exist (%s)", dir) + return "", errors.Join(fmt.Errorf("file does not exist (%s)", dir), ErrConfigFileNotFound) } return dir, nil } home, err := getHomeDir() if err != nil { - return "", fmt.Errorf("user home dir: %w", err) + return "", errors.Join(fmt.Errorf("user home dir: %w", err), ErrConfigFileNotFound) } configDir := filepath.Join(home, configFileDir) if !fileExists(configDir) { - return "", fmt.Errorf("file does not exist (%s)", configDir) + return "", errors.Join(fmt.Errorf("file does not exist (%s)", configDir), ErrConfigFileNotFound) } return configDir, nil @@ -110,6 +110,7 @@ func Load() (Config, error) { cfg, err = loadFromFilepath(p) if errors.Is(err, os.ErrNotExist) { + cfg.filepath = p return cfg, nil } if err != nil { From 99e653fc071b3681e59e23ebed99b56731d51cf2 Mon Sep 17 00:00:00 2001 From: Fabrizio Gomez Date: Mon, 22 Jun 2026 20:40:36 -0600 Subject: [PATCH 08/10] fix(config): The sentinel error for missing config file should not be present when it is the homedir that is missing --- config/load.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/load.go b/config/load.go index 5f623bc0..b261ee52 100644 --- a/config/load.go +++ b/config/load.go @@ -54,7 +54,7 @@ func Dir() (string, error) { home, err := getHomeDir() if err != nil { - return "", errors.Join(fmt.Errorf("user home dir: %w", err), ErrConfigFileNotFound) + return "", fmt.Errorf("user home dir: %w", err) } configDir := filepath.Join(home, configFileDir) From 7bae07e642af135b828ce7047c81a861e25893d8 Mon Sep 17 00:00:00 2001 From: Fabrizio Gomez Date: Mon, 22 Jun 2026 20:41:53 -0600 Subject: [PATCH 09/10] test(config): Add more tests for the directory missing new codepath --- config/auth_missing_config_test.go | 44 ++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/config/auth_missing_config_test.go b/config/auth_missing_config_test.go index faeea013..322f136f 100644 --- a/config/auth_missing_config_test.go +++ b/config/auth_missing_config_test.go @@ -3,6 +3,7 @@ package config import ( "errors" "os/exec" + "path/filepath" "testing" "github.com/stretchr/testify/require" @@ -16,6 +17,14 @@ func setupConfigDirWithoutFile(t *testing.T) { t.Setenv(EnvOverrideDir, t.TempDir()) } +// setupNonExistentConfigDir points DOCKER_CONFIG at a path that does not exist, +// exercising the ErrConfigFileNotFound code path in Dir() when the config +// directory itself is missing (a common fresh-install state). +func setupNonExistentConfigDir(t *testing.T) { + t.Helper() + t.Setenv(EnvOverrideDir, filepath.Join(t.TempDir(), "does-not-exist")) +} + func TestAuthConfigs_ConfigNotFound(t *testing.T) { setupConfigDirWithoutFile(t) mockExecCommand(t) @@ -77,3 +86,38 @@ func TestFilepath_ConfigNotFound_ReturnsSentinel(t *testing.T) { require.ErrorIs(t, err, ErrConfigFileNotFound) require.Contains(t, err.Error(), "config file does not exist") } + +func TestDir_ConfigDirNotFound_ReturnsSentinel(t *testing.T) { + setupNonExistentConfigDir(t) + + _, err := Dir() + require.ErrorIs(t, err, ErrConfigFileNotFound) + require.Contains(t, err.Error(), "file does not exist") +} + +func TestDir_DefaultConfigDirNotFound_ReturnsSentinel(t *testing.T) { + // Point HOME at a temp dir without a .docker subdirectory, and clear + // DOCKER_CONFIG so Dir() falls back to the default ~/.docker path. + tmpHome := t.TempDir() + t.Setenv("HOME", tmpHome) + t.Setenv("USERPROFILE", tmpHome) // Windows support + t.Setenv(EnvOverrideDir, "") + + _, err := Dir() + require.ErrorIs(t, err, ErrConfigFileNotFound) + require.Contains(t, err.Error(), "file does not exist") +} + +func TestFilepath_ConfigDirNotFound_ReturnsSentinel(t *testing.T) { + setupNonExistentConfigDir(t) + + _, err := Filepath() + require.ErrorIs(t, err, ErrConfigFileNotFound) +} + +func TestLoad_ConfigDirNotFound_ReturnsSentinel(t *testing.T) { + setupNonExistentConfigDir(t) + + _, err := Load() + require.ErrorIs(t, err, ErrConfigFileNotFound) +} From cd25cb8e29acab8c4d355bec1698c998ebbec97d Mon Sep 17 00:00:00 2001 From: Fabrizio Gomez Date: Mon, 22 Jun 2026 20:55:26 -0600 Subject: [PATCH 10/10] fix(config): Update the code paths so that the sentined is being used only when the config path has not been overwritten --- config/auth_missing_config_test.go | 21 +++++++++++++-------- config/load.go | 2 +- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/config/auth_missing_config_test.go b/config/auth_missing_config_test.go index 322f136f..ec07bd4d 100644 --- a/config/auth_missing_config_test.go +++ b/config/auth_missing_config_test.go @@ -18,8 +18,10 @@ func setupConfigDirWithoutFile(t *testing.T) { } // setupNonExistentConfigDir points DOCKER_CONFIG at a path that does not exist, -// exercising the ErrConfigFileNotFound code path in Dir() when the config -// directory itself is missing (a common fresh-install state). +// exercising the hard-fail code path in Dir() when an explicitly overridden +// config directory is missing. Unlike the default ~/.docker case, an explicit +// DOCKER_CONFIG pointing at a non-existent path is a user error and must NOT +// surface ErrConfigFileNotFound. func setupNonExistentConfigDir(t *testing.T) { t.Helper() t.Setenv(EnvOverrideDir, filepath.Join(t.TempDir(), "does-not-exist")) @@ -87,11 +89,12 @@ func TestFilepath_ConfigNotFound_ReturnsSentinel(t *testing.T) { require.Contains(t, err.Error(), "config file does not exist") } -func TestDir_ConfigDirNotFound_ReturnsSentinel(t *testing.T) { +func TestDir_OverriddenConfigDirNotFound_NoSentinel(t *testing.T) { setupNonExistentConfigDir(t) _, err := Dir() - require.ErrorIs(t, err, ErrConfigFileNotFound) + require.Error(t, err) + require.NotErrorIs(t, err, ErrConfigFileNotFound) require.Contains(t, err.Error(), "file does not exist") } @@ -108,16 +111,18 @@ func TestDir_DefaultConfigDirNotFound_ReturnsSentinel(t *testing.T) { require.Contains(t, err.Error(), "file does not exist") } -func TestFilepath_ConfigDirNotFound_ReturnsSentinel(t *testing.T) { +func TestFilepath_OverriddenConfigDirNotFound_NoSentinel(t *testing.T) { setupNonExistentConfigDir(t) _, err := Filepath() - require.ErrorIs(t, err, ErrConfigFileNotFound) + require.Error(t, err) + require.NotErrorIs(t, err, ErrConfigFileNotFound) } -func TestLoad_ConfigDirNotFound_ReturnsSentinel(t *testing.T) { +func TestLoad_OverriddenConfigDirNotFound_NoSentinel(t *testing.T) { setupNonExistentConfigDir(t) _, err := Load() - require.ErrorIs(t, err, ErrConfigFileNotFound) + require.Error(t, err) + require.NotErrorIs(t, err, ErrConfigFileNotFound) } diff --git a/config/load.go b/config/load.go index b261ee52..c2be6d87 100644 --- a/config/load.go +++ b/config/load.go @@ -47,7 +47,7 @@ func Dir() (string, error) { dir := os.Getenv(EnvOverrideDir) if dir != "" { if !fileExists(dir) { - return "", errors.Join(fmt.Errorf("file does not exist (%s)", dir), ErrConfigFileNotFound) + return "", fmt.Errorf("file does not exist (%s)", dir) } return dir, nil }