Repository: spf13/viper (Go)

Issue:
viper.ConfigFileNotFoundError when file most definitely exists.
```
~/P/g/s/e/b/rbaapi ❯❯❯ DEBUG=1 go run main.go register 89a1029f-bdaa-41f0-811e-66ef878faabb
viper.ConfigFileNotFoundError{name:".rbaapi", locations:"[/Users/xguzman]"}
<nil>Error: Unable to convert defined API DSN into a string
Usage:
  rbaapi register <UUID> [flags]

Global Flags:
      --config string   config file (default is $HOME/.rbaapi)

Unable to convert defined API DSN into a string
exit status 255
~/P/g/s/e/b/rbaapi ❯❯❯ file /Users/xguzman/.rbaapi                                                                                                                                                                                                                                                                                                                        ⏎
/Users/xguzman/.rbaapi: ASCII text
~/P/g/s/e/b/rbaapi ❯❯❯ ls -al /Users/xguzman/.rbaapi
-rw-r--r--@ 1 xguzman  staff  80 Apr 20 08:26 /Users/xguzman/.rbaapi
```
config file not found
hello,i code the example:
         viper.SetConfigType("yaml")
        //viper.SetConfigFile("/etc/config.yaml")
        viper.SetConfigName("config.yaml")
        viper.AddConfigPath("/etc")
        err := viper.ReadInConfig()
        if err != nil {
                fmt.Println(err)
        }
or
        viper.SetConfigType("yaml")
        viper.SetConfigFile("config.yaml")
        //viper.SetConfigName("config.yaml")
        viper.AddConfigPath("/etc")
        err := viper.ReadInConfig()
        if err != nil {
                fmt.Println(err)
        }
i'm sure that i have config.yaml in /etc dirctionary,but the outputs of these  code are:
Config File "config.yaml" Not Found in "[/etc]"
open config.yaml: no such file or directory
what's wrong?


Discussion:
I figured it out. The code checks for **filename.ext**. Even when specifying the config file with --config. This is unexpected behavior.

Just to clarify, if the default file is named `.rbaapi` then the library will check for `.rbaapi.yaml`, `.rbaapi.yml`, etc... even if you specify an absolute file path with the `--config` flag. Though clever, this isn't clearly documented and not expected behavior.

I'm not sure but maybe try
``` go
viper.SetConfigType("yaml")
viper.SetConfigName("config")
viper.AddConfigPath("/etc")
err := viper.ReadInConfig()
if err != nil {
  fmt.Println(err)
}
```

or try

``` go
viper.SetConfigFile("config.yaml")
viper.AddConfigPath("/etc")
err := viper.ReadInConfig()
if err != nil {
   fmt.Println(err)
}
```
I confirm the issue with "not found" configuration. The proposed solution doesn't solve it.
It looks that config name should be without any extension (**viper.SetConfigName(...)**) while the actual file should have any supported extension. Take a look into https://github.com/spf13/viper/blob/d9cca5ef33035202efb1586825bdbb15ff9ec3ba/viper.go#L1536 

@nad2000 is correct. `searchInPath` concatenates search path, file name and extension. Which appears to be the intended behaviour. `filepath.Join(in, v.configName+"."+ext)`

So viper will search, your filepaths + filename + extension:
```
/Users/example/go/src/github.com/your-app/config.json
/Users/example/go/src/github.com/your-app/config.toml
/Users/example/go/src/github.com/your-app/config.yaml
/Users/example/go/src/github.com/your-app/config.yml
/Users/example/go/src/github.com/your-app/config.properties
/Users/example/go/src/github.com/your-app/config.props
/Users/example/go/src/github.com/your-app/config.prop
/Users/example/go/src/github.com/your-app/config.hcl
```

Instead, what you could do is specify the file type yourself via:
`viper.SetConfigType("yaml")`

and pass in the absolute path to your config file via:
`viper.SetConfigFile("/etc/configs/config")`

or if the config file will always be in the same directory as main application:
`viper.SetConfigFile("config")`
How much time did I waste on this!? It should be documented clearly that specifying what data serialization format your config file uses, will modify the name that is searched for by appending an extension to the file name. 
Message removed... I messed up with the folder names... :disappointed_relieved:
Instead of using `AddConfigPath` try the following:

```go
// set the config file type
viper.SetConfigType("yaml")

// specify where the config file is
viper.SetConfigFile("./config/config") // or viper.SetConfigFile("config/config"), doesn't matter

// read in config file and check your errors
if err := viper.ReadInConfig(); err != nil {
  // handle errors
}

// confirm where the file has been read in from
fmt.Println(viper.ConfigFileUsed())
```
This looks real issue as it always require complete path with file name for search. AddConfigPath() doesn't work in the case where config file is in other directory.  @mfridman @nad2000 
for me `SetConfigName` and `AddConfigPath` without `SetConfigFile` works

my conf file is at `/secrets/app.yaml`
```
	Config.SetConfigType("yaml")
	Config.AddConfigPath("/secrets/")
	Config.SetConfigName("app")
	err := Config.ReadInConfig()
```

this is because if you set ConfigFile it takes the file as the absolute path instead of searching for that file in the list of config paths

https://github.com/spf13/viper/blob/d9cca5ef33035202efb1586825bdbb15ff9ec3ba/viper.go#L1521-L1534

any update now?
> Instead of using `AddConfigPath` try the following:
> 
> ```go
> // set the config file type
> viper.SetConfigType("yaml")
> 
> // specify where the config file is
> viper.SetConfigFile("./config/config") // or viper.SetConfigFile("config/config"), doesn't matter
> 
> // read in config file and check your errors
> if err := viper.ReadInConfig(); err != nil {
>   // handle errors
> }
> 
> // confirm where the file has been read in from
> fmt.Println(viper.ConfigFileUsed())
> ```

Thanks!!  I solve my issue with this reply
> > Instead of using `AddConfigPath` try the following:
> > ```go
> > // set the config file type
> > viper.SetConfigType("yaml")
> > 
> > // specify where the config file is
> > viper.SetConfigFile("./config/config") // or viper.SetConfigFile("config/config"), doesn't matter
> > 
> > // read in config file and check your errors
> > if err := viper.ReadInConfig(); err != nil {
> >   // handle errors
> > }
> > 
> > // confirm where the file has been read in from
> > fmt.Println(viper.ConfigFileUsed())
> > ```
> 
> Thanks!! I solve my issue with this reply

Neither Get nor SetConfigFile is working for me. I keep getting 'no such file'
> > > Instead of using `AddConfigPath` try the following:
> > > ```go
> > > // set the config file type
> > > viper.SetConfigType("yaml")
> > > 
> > > // specify where the config file is
> > > viper.SetConfigFile("./config/config") // or viper.SetConfigFile("config/config"), doesn't matter
> > > 
> > > // read in config file and check your errors
> > > if err := viper.ReadInConfig(); err != nil {
> > >   // handle errors
> > > }
> > > 
> > > // confirm where the file has been read in from
> > > fmt.Println(viper.ConfigFileUsed())
> > > ```
> > 
> > 
> > Thanks!! I solve my issue with this reply
> 
> Neither Get nor SetConfigFile is working for me. I keep getting 'no such file'

Use this instead....

`viper.SetConfigType("yaml")`
`viper.SetConfigName("configName")`
`viper.AddConfigPath("/path/to/config/file")`
`err := viper.ReadInConfig()`
`if err != nil {`
`   // Handle Error`
` ...`
`}`
It's looks like `viper.AddConfigPath(".")`  dosn't work correct now, must be specified a absolut path...
> It's looks like `viper.AddConfigPath(".")` dosn't work correct now, must be specified a absolut path...

But it doesn't work
The same problem happen to me.  I use following method solve it.

viper.SetConfigType("yaml")
viper.SetConfigFile("/path/to/config/file/configName")
err := viper.ReadInConfig()
if err != nil {
// Handle Error
...
}
You can add multiple `viper.AddConfigPath()`lines based on commented code, https://github.com/spf13/viper/blob/master/viper.go#L411

`viper.AddConfigPath("./")`
`viper.AddConfigPath("../")`
@sagikazarmark this should be reopened as I mistakenly marked #722 as solving #390 . Thanks to @andig (https://github.com/spf13/viper/pull/722#issuecomment-572988072) for bringing this to attention.
Unfortunately, I can't really tell anymore what this issue is about, but I get the feeling it's rather a documentation problem than an actual bug in the code.
Re-reading this thread it seems the problem might be in the `AddConfigPath` as this comment https://github.com/spf13/viper/issues/390#issuecomment-511177615 seems to suggest

Assume your configs file in `/home/ubuntu/go/bin/myapp/configs/conf.env`
Your code should provide  :
if run from `/home/ubuntu/go/bin/myapp/configs/` then set `viper.AddConfigPath(".") `
if run from `/home/ubuntu/go/bin/myapp/` then set `viper.AddConfigPath("./configs")`
if run from `/home/ubuntu/go/bin/` then set `viper.AddConfigPath("./myapp/configs")`
if run from root of Ubuntu machine (such as make it as a service) 
then set `viper.AddConfigPath("/home/ubuntu/go/bin/myapp/configs/")`



It doesn't work for production version
Works for me in production:

```go
_, filePath, _, _ := runtime.Caller(0)
configFile := filePath[:len(filePath)-9]
viper.SetConfigFile(configFile + string(filepath.Separator) + ".env")
err := viper.ReadInConfig()
```
Just had following problem:(using an existing configfile "myConfig.json")
```go
v := viper.New()
v.SetConfigName("myConfig.json")
v.SetConfigType("json")
v.AddConfigPath(".")

err := v.ReadInConfig()
if err != nil {
	log.Panicf("Fatal error config file: %s", err)
}
```

Without "SetConfigType" the error is thrown ...

```go
v := viper.New()
v.SetConfigName("myConfig.json")
// v.SetConfigType("json")   => Omitting setting config type, leads to error condition, unless config name contains extension
v.AddConfigPath(".")

err := v.ReadInConfig()
if err != nil {
	log.Panicf("Fatal error config file: %s", err)
}
```
Running: go version go1.14.2 windows/amd64

Worked in Win10 (using GoLand)!! 😃 

```go
// Set the file name of the configurations file
viper.SetConfigName("config")

// Set the configuration file type
viper.SetConfigType("yaml")

// Set the path to look for the configurations file
viper.AddConfigPath("./config")

// Find and read the config file
err := viper.ReadInConfig()
if err != nil {
	fmt.Printf("Error reading config file, %s", err)
	return err
}
```

BTW `viper.SetConfigName("config.yml")` did not work.

Can confirm `viper.SetConfigFile` does not work, the way to fix it was to add the directory the configuration would be present in using `AddConfigPath`
How we handled this fckn problem? I m trying for 2 day  . . .
This was very frustrating to deal with. For me, I finally figured out that you cannot use SetConfigFile() in conjunction with anything else. It can only be the path to the config file. If you use this method, it will ignore any paths and ONLY use the value passed to SetConfigFile() 

In this example, my file is named fileNameNoExtension.yaml on disk.
```
      configFileName := "fileNameNoExtension"
        mydir = "/a/dir"
	viper.AddConfigPath(mydir)
	viper.SetConfigType("yaml")
	viper.SetConfigName(configFileName)
	//viper.SetConfigFile()

```
if I uncomment the last line, all previous lines are ignored and the config file fails to resolve.
Can successfully read my configuration after setting the `ConfigType` as suggested by the first answer.

```go
var (
    _, b, _, _ = runtime.Caller(0)
    root       = filepath.Join(filepath.Dir(b), "../..")
)

func main() {
    viper.AddConfigPath(root)
    viper.SetConfigType("yaml") // This work
    viper.SetConfigName("my-config-file")
    _ = viper.ReadInConfig()
    ...    

```

```go
var (
    _, b, _, _ = runtime.Caller(0)
    root       = filepath.Join(filepath.Dir(b), "../..")
)

func main() {
    viper.AddConfigPath(root)
    viper.SetConfigName("my-config-file.yaml") // This doesn't work
    _ = viper.ReadInConfig()
    ...    

```
you need to ensure you only use one of the two approaches, either specify the file by the full config file name or let viper figure it out.

```
viper.SetConfigFile("full-name-of-file-including-path-and-extension-if-any")
```
OR

```
viper.AddConfigPath("search-path-1") // repeat as needed to add places to look for the config file
viper.SetConfigType("yaml") // or whatever supported format the file is in, if not specified then it'll try all it supports
viper.SetConfigName("name-of-the-config-file-which-has-an-extension-but-without-the-extension")
```
So to read in the config file in YAML format placed at `/etc/example/configfile.yaml`, you would use either of the below.
```
viper.SetConfigFile("/etc/example/configfile.yaml")
```
OR
```
viper.AddConfigPath("/etc/example")
viper.SetConfigType("yaml")
viper.SetConfigName("configfile")
```

Here's a gist for some examples https://gist.github.com/gwvandesteeg/939c05ac34518d65c49a94b2dbdd7cec

Still is broken. Wtf...
it seems like doc is wrong 
> viper.SetConfigType("yaml") // REQUIRED if the config file does not have the extension in the name

For me 

this one worked
```golang
viper.SetConfigName("config")
viper.SetConfigType("yaml")
viper.AddConfigPath(...)
viper.AddConfigPath(...)
```

this not
```golang
viper.SetConfigName("config.yaml")
viper.AddConfigPath(...)
viper.AddConfigPath(...)
```

I'm having the same issue, i tried all the methods above but none of them worked for me
```golang
viper.SetConfigType("yaml")
viper.AddConfigPath("../configs")
viper.SetConfigName("config")
```
Update your env AddConfigPath with ../env or ../../env 
Issues with no activity for 30 days are marked stale and subject to being closed.
This issue has been closed for inactivity. Please re-open if this was a mistake.



Patch:
diff --git a/README.md b/README.md
index 171f51ccb..fe292d0b3 100644
--- a/README.md
+++ b/README.md
@@ -121,6 +121,8 @@ if err := viper.ReadInConfig(); err != nil {
 // Config file found and successfully parsed
 ```
 
+*NOTE:* You can also have a file without an extension and specify the format programmaticaly. For those configuration files that lie in the home of the user without any extension like `.bashrc`
+
 ### Writing Config Files
 
 Reading from config files is useful, but at times you want to store all modifications made at run time.
diff --git a/viper.go b/viper.go
index e9010bc90..c64094a17 100644
--- a/viper.go
+++ b/viper.go
@@ -1881,6 +1881,10 @@ func (v *Viper) searchInPath(in string) (filename string) {
 		}
 	}
 
+	if b, _ := exists(v.fs, filepath.Join(in, v.configName)); b {
+		return filepath.Join(in, v.configName)
+	}
+
 	return ""
 }
 


Test patch:
diff --git a/viper_test.go b/viper_test.go
index f8364a044..8dcfd1a01 100644
--- a/viper_test.go
+++ b/viper_test.go
@@ -278,6 +278,22 @@ func TestBasics(t *testing.T) {
 	assert.NoError(t, err)
 }
 
+func TestSearchInPath(t *testing.T) {
+	filename := ".dotfilenoext"
+	path := "/tmp"
+	file := filepath.Join(path, filename)
+	SetConfigName(filename)
+	AddConfigPath(path)
+	_, createErr := v.fs.Create(file)
+	defer func() {
+		_ = v.fs.Remove(file)
+	}()
+	assert.NoError(t, createErr)
+	filename, err := v.getConfigFile()
+	assert.Equal(t, file, filename)
+	assert.NoError(t, err)
+}
+
 func TestDefault(t *testing.T) {
 	SetDefault("age", 45)
 	assert.Equal(t, 45, Get("age"))