ronantakizawa/codereview-bench huggingface dataset:
Repository: spf13/viper
File: viper.go (Go)

Code before:
				var val interface{}
				switch n := next.(type) {
				case map[interface{}]interface{}:
					val = v.searchMapWithPathPrefixes(cast.ToStringMap(next), path[i:])
				case map[string]interface{}, []interface{}:
					val = v.searchMapWithPathPrefixes(n, path[i:])
				default:
					// got a value but nested key expected, do nothing and look for next prefix
				}
				if val != nil {
					return val
				}
			}
		} else if sourceMap, ok := source.(map[string]interface{}); ok {
			next, ok := sourceMap[prefixKey]
			if ok {
				// Fast path
				if i == len(path) {
					return next
				}

				// Nested case
				var val interface{}
				switch n := next.(type) {
				case map[interface{}]interface{}:
					val = v.searchMapWithPathPrefixes(cast.ToStringMap(next), path[i:])
				case map[string]interface{}, []interface{}:
					val = v.searchMapWithPathPrefixes(n, path[i:])
				default:
					// got a value but nested key expected, do nothing and look for next prefix
				}
				if val != nil {
					return val
				}
			}
		}
	}

	// not found
	return nil
}

// isPathShadowedInDeepMap makes sure the given path is not shadowed somewhere
// on its path in the map.
// e.g., if "foo.bar" has a value in the given map, it “shadows”
//       "foo.bar.baz" in a lower-priority map
func (v *Viper) isPathShadowedInDeepMap(path []string, m map[string]interface{}) string {
	var parentVal interface{}
	for i := 1; i < len(path); i++ {
		parentVal = v.searchMap(m, path[0:i])
		if parentVal == nil {

Review comment (suggestion):
```suggestion
					val = v.searchMapWithPathPrefixes(cast.ToStringMap(n), path[i:])
```

Code after:
		case map[string]interface{}:
			val = v.searchMapWithPathPrefixes(sourceIndexable, prefixKey, i, path)
		}
		if val != nil {
			return val
		}
	}

	// not found
	return nil
}

// searchSliceWithPathPrefixes searches for a value for path in sourceSlice
//
// This function is part of the searchIndexableWithPathPrefixes recurring search and
// should not be called directly from functions other than searchIndexableWithPathPrefixes.
func (v *Viper) searchSliceWithPathPrefixes(
	sourceSlice []interface{},
	prefixKey string,
	pathIndex int,
	path []string,
) interface{} {
	// if the prefixKey is not a number or it is out of bounds of the slice
	index, err := strconv.Atoi(prefixKey)
	if err != nil || len(sourceSlice) <= index {
		return nil
	}

	next := sourceSlice[index]

	// Fast path
	if pathIndex == len(path) {
		return next
	}

	switch n := next.(type) {
	case map[interface{}]interface{}:
		return v.searchIndexableWithPathPrefixes(cast.ToStringMap(n), path[pathIndex:])
	case map[string]interface{}, []interface{}:
		return v.searchIndexableWithPathPrefixes(n, path[pathIndex:])
	default:
		// got a value but nested key expected, do nothing and look for next prefix
	}

	// not found
	return nil
}

// searchMapWithPathPrefixes searches for a value for path in sourceMap
//
// This function is part of the searchIndexableWithPathPrefixes recurring search and
Repository: spf13/viper
File: viper.go (Go)

Code before:
	}
	f, err := v.fs.OpenFile(filename, flags, v.configPermissions)
	if err != nil {
		return err
	}
	defer f.Close()

	if err := v.marshalWriter(f, configType); err != nil {
		return err
	}

	return f.Sync()
}

func (v *Viper) unmarshalReader(in io.Reader, c map[string]any) error {
	buf := new(bytes.Buffer)
	buf.ReadFrom(in)

	switch format := strings.ToLower(v.getConfigType()); format {
	case "yaml", "yml", "json", "toml", "hcl", "tfvars", "ini", "properties", "props", "prop", "dotenv", "env":
		decoder, ok := v.decoderRegistry2.Decoder(format)
		if !ok {
			return ConfigParseError{errors.New("decoder not found")}
		}

		err := decoder.Decode(buf.Bytes(), c)
		if err != nil {
			return ConfigParseError{err}
		}
	}

	insensitiviseMap(c)
	return nil
}

// Marshal a map into Writer.
func (v *Viper) marshalWriter(f afero.File, configType string) error {
	c := v.AllSettings()
	switch configType {
	case "yaml", "yml", "json", "toml", "hcl", "tfvars", "ini", "prop", "props", "properties", "dotenv", "env":
		encoder, ok := v.encoderRegistry2.Encoder(configType)
		if !ok {
			// TODO: return a proper error
			return ConfigMarshalError{errors.New("encoder not found")}
		}

		b, err := encoder.Encode(c)
		if err != nil {
			return ConfigMarshalError{err}
		}


Review comment (suggestion):
```suggestion
		if err := decoder.Decode(buf.Bytes(), c); err !=nil {
```

Code after:
	return tgt
}

// mergeMaps merges two maps. The `itgt` parameter is for handling go-yaml's
// insistence on parsing nested structures as `map[any]any`
// instead of using a `string` as the key for nest structures beyond one level
// deep. Both map types are supported as there is a go-yaml fork that uses
// `map[string]any` instead.
func mergeMaps(src, tgt map[string]any, itgt map[any]any) {
	for sk, sv := range src {
		tk := keyExists(sk, tgt)
		if tk == "" {
			v.logger.Debug("", "tk", "\"\"", fmt.Sprintf("tgt[%s]", sk), sv)
			tgt[sk] = sv
			if itgt != nil {
				itgt[sk] = sv
			}
			continue
		}

		tv, ok := tgt[tk]
		if !ok {
			v.logger.Debug("", fmt.Sprintf("ok[%s]", tk), false, fmt.Sprintf("tgt[%s]", sk), sv)
			tgt[sk] = sv
			if itgt != nil {
				itgt[sk] = sv
			}
			continue
		}

		svType := reflect.TypeOf(sv)
		tvType := reflect.TypeOf(tv)

		v.logger.Debug(
			"processing",
			"key", sk,
			"st", svType,
			"tt", tvType,
			"sv", sv,
			"tv", tv,
		)

		switch ttv := tv.(type) {
		case map[any]any:
			v.logger.Debug("merging maps (must convert)")
			tsv, ok := sv.(map[any]any)
			if !ok {
				v.logger.Error(
					"Could not cast sv to map[any]any",
					"key", sk,
					"st", svType,
Repository: spf13/viper
File: viper.go (Go)

Code before:
	// set innermost value
	deepestMap[lastKey] = value
}

// ReadInConfig will discover and load the configuration file from disk
// and key/value stores, searching in one of the defined paths.
func ReadInConfig() error { return v.ReadInConfig() }

func (v *Viper) ReadInConfig() error {
	v.logger.Info("attempting to read in config file")
	filename, err := v.getConfigFile()
	if err != nil {
		return err
	}

	if !slices.Contains(SupportedExts, v.getConfigType()) {
		return UnsupportedConfigError(v.getConfigType())
	}

	v.logger.Debug("reading file", "file", filename)
	exists, err := afero.Exists(v.fs, filename)
	if !exists {
		return ConfigFileNotFoundError{filename, ""}
	} else if err != nil {
		return err
	}
	file, err := afero.ReadFile(v.fs, filename)
	if err != nil {
		return err
	}
	config := make(map[string]any)

	err = v.unmarshalReader(bytes.NewReader(file), config)
	if err != nil {
		return err
	}

	v.config = config
	return nil
}

// MergeInConfig merges a new configuration with an existing config.
func MergeInConfig() error { return v.MergeInConfig() }

func (v *Viper) MergeInConfig() error {
	v.logger.Info("attempting to merge in config file")
	filename, err := v.getConfigFile()
	if err != nil {
		return err
	}


Review comment (suggestion):
Any reason to do not use the idiomatic way to check error first? 

```suggestion
	if err != nil {
		return err
	}

	if !exists {
		return ConfigFileNotFoundError{filename, ""}
	}
```


Code after:

	v.config = config
	return nil
}

// MergeInConfig merges a new configuration with an existing config.
func MergeInConfig() error { return v.MergeInConfig() }

func (v *Viper) MergeInConfig() error {
	v.logger.Info("attempting to merge in config file")
	filename, err := v.getConfigFile()
	if err != nil {
		return err
	}

	if !slices.Contains(SupportedExts, v.getConfigType()) {
		return UnsupportedConfigError(v.getConfigType())
	}

	file, err := afero.ReadFile(v.fs, filename)
	if err != nil {
		return err
	}

	return v.MergeConfig(bytes.NewReader(file))
}

// ReadConfig will read a configuration file, setting existing keys to nil if the
// key does not exist in the file.
func ReadConfig(in io.Reader) error { return v.ReadConfig(in) }

func (v *Viper) ReadConfig(in io.Reader) error {
	config := make(map[string]any)

	err := v.unmarshalReader(in, config)
	if err != nil {
		return err
	}

	v.config = config

	return nil
}

// MergeConfig merges a new configuration with an existing config.
func MergeConfig(in io.Reader) error { return v.MergeConfig(in) }

func (v *Viper) MergeConfig(in io.Reader) error {
	config := make(map[string]any)

	if err := v.unmarshalReader(in, config); err != nil {
Repository: spf13/viper
File: viper.go (Go)

Code before:
	lastKey := strings.ToLower(path[len(path)-1])
	deepestMap := deepSearch(v.override, path[0:len(path)-1])

	// set innermost value
	deepestMap[lastKey] = value
}

// ReadInConfig will discover and load the configuration file from disk
// and key/value stores, searching in one of the defined paths.
func ReadInConfig() error { return v.ReadInConfig() }

func (v *Viper) ReadInConfig() error {
	v.logger.Info("attempting to read in config file")
	filename, err := v.getConfigFile()
	if err != nil {
		return err
	}

	if !slices.Contains(SupportedExts, v.getConfigType()) {
		return UnsupportedConfigError(v.getConfigType())
	}

	v.logger.Debug("reading file", "file", filename)
	exists, err := afero.Exists(v.fs, filename)
	if !exists {
		return ConfigFileNotFoundError{filename, ""}
	} else if err != nil {
		return err
	}
	file, err := afero.ReadFile(v.fs, filename)
	if err != nil {
		return err
	}
	config := make(map[string]any)

	err = v.unmarshalReader(bytes.NewReader(file), config)
	if err != nil {
		return err
	}

	v.config = config
	return nil
}

// MergeInConfig merges a new configuration with an existing config.
func MergeInConfig() error { return v.MergeInConfig() }

func (v *Viper) MergeInConfig() error {
	v.logger.Info("attempting to merge in config file")
	filename, err := v.getConfigFile()
	if err != nil {

Review comment (suggestion):
I didn't check surrounding code, but here the object should be initialized with field names. This would avoid compilation issue if a field is added to this struct.

```suggestion
		return ConfigFileNotFoundError{name: filename}
```


Code after:
	if err != nil {
		return err
	}

	v.config = config
	return nil
}

// MergeInConfig merges a new configuration with an existing config.
func MergeInConfig() error { return v.MergeInConfig() }

func (v *Viper) MergeInConfig() error {
	v.logger.Info("attempting to merge in config file")
	filename, err := v.getConfigFile()
	if err != nil {
		return err
	}

	if !slices.Contains(SupportedExts, v.getConfigType()) {
		return UnsupportedConfigError(v.getConfigType())
	}

	file, err := afero.ReadFile(v.fs, filename)
	if err != nil {
		return err
	}

	return v.MergeConfig(bytes.NewReader(file))
}

// ReadConfig will read a configuration file, setting existing keys to nil if the
// key does not exist in the file.
func ReadConfig(in io.Reader) error { return v.ReadConfig(in) }

func (v *Viper) ReadConfig(in io.Reader) error {
	config := make(map[string]any)

	err := v.unmarshalReader(in, config)
	if err != nil {
		return err
	}

	v.config = config

	return nil
}

// MergeConfig merges a new configuration with an existing config.
func MergeConfig(in io.Reader) error { return v.MergeConfig(in) }

func (v *Viper) MergeConfig(in io.Reader) error {
Repository: spf13/viper
File: errors.go (Go)

Code before:
package viper

import (
	"fmt"
)

/* ConfigFileNotFoundError types */

// For matching on any ConfigFileNotFoundFrom*Error.
type ConfigFileNotFoundError interface {
	Error() string
	Name() string
	Locations() string
}

// ConfigFileNotFoundFromFinderError denotes failing to find a configuration file.
type ConfigFileNotFoundFromFinderError struct {
	name, locations string
}

// Error returns the formatted configuration error.
func (fnfe ConfigFileNotFoundFromFinderError) Error() string {
	message := fmt.Sprintf("Config file %q Not Found", fnfe.name)
	if fnfe.locations != "" {
		message += fmt.Sprintf(" in %q", fnfe.locations)
	}

	return message
}

func (fnfe ConfigFileNotFoundFromFinderError) Name() string {
	return fnfe.name
}

func (fnfe ConfigFileNotFoundFromFinderError) Locations() string {
	return fnfe.locations
}

// ConfigFileNotFoundFromReadError denotes failing to find a specific configuration file.

Review comment (suggestion):
I've never been fond of the `Config` prefix. I'd also look for a less ambiguous name:

```suggestion
// FileLookupError is returned when Viper cannot resolve a configuration file,
// either because a file does not exists or because it cannot find any file matching the criteria.
type FileLookupError interface {
	error
	
	fileLookup()
}
```

The private function is to make it a marker interface distinguished from `error`.

I don't think Name and location are necessary for the interface. If anyone is interested in those details, they should handle the individual types.

Code after:
package viper

import (
	"fmt"
)

// FileLookupError is returned when Viper cannot resolve a configuration file.
//
// This is meant to be a common interface for all file look-up errors, occurring either because a
// file does not exist or because it cannot find any file matching finder criteria.
type FileLookupError interface {
	error

	fileLookup()
}

// ConfigFileNotFoundError denotes failing to find a configuration file from a search.
//
// Deprecated: This is error wraps [FileNotFoundFromSearchError], which should be used instead.
type ConfigFileNotFoundError struct {
	locations []string
	name      string
}

// Error returns the formatted error.
func (e ConfigFileNotFoundError) Error() string {
	return e.Unwrap().Error()
}

// Unwraps to FileNotFoundFromSearchError.
func (e ConfigFileNotFoundError) Unwrap() error {
	return FileNotFoundFromSearchError(e)
}

// FileNotFoundFromSearchError denotes failing to find a configuration file from a search.
// Wraps ConfigFileNotFoundError.
type FileNotFoundFromSearchError struct {
	locations []string
	name      string
Repository: spf13/viper
File: errors.go (Go)

Code before:
package viper

import (
	"fmt"
)

/* ConfigFileNotFoundError types */

// For matching on any ConfigFileNotFoundFrom*Error.
type ConfigFileNotFoundError interface {
	Error() string
	Name() string
	Locations() string
}

// ConfigFileNotFoundFromFinderError denotes failing to find a configuration file.
type ConfigFileNotFoundFromFinderError struct {
	name, locations string
}

// Error returns the formatted configuration error.
func (fnfe ConfigFileNotFoundFromFinderError) Error() string {
	message := fmt.Sprintf("Config file %q Not Found", fnfe.name)
	if fnfe.locations != "" {
		message += fmt.Sprintf(" in %q", fnfe.locations)
	}

	return message
}

func (fnfe ConfigFileNotFoundFromFinderError) Name() string {
	return fnfe.name
}

func (fnfe ConfigFileNotFoundFromFinderError) Locations() string {
	return fnfe.locations
}

// ConfigFileNotFoundFromReadError denotes failing to find a specific configuration file.
type ConfigFileNotFoundFromReadError struct {
	name string
}

Review comment (suggestion):
I would call this something like `CouldNotLocateFileError` or `NoFileSearchResultsError` or something similar.

Code after:
package viper

import (
	"fmt"
)

// FileLookupError is returned when Viper cannot resolve a configuration file.
//
// This is meant to be a common interface for all file look-up errors, occurring either because a
// file does not exist or because it cannot find any file matching finder criteria.
type FileLookupError interface {
	error

	fileLookup()
}

// ConfigFileNotFoundError denotes failing to find a configuration file from a search.
//
// Deprecated: This is error wraps [FileNotFoundFromSearchError], which should be used instead.
type ConfigFileNotFoundError struct {
	locations []string
	name      string
}

// Error returns the formatted error.
func (e ConfigFileNotFoundError) Error() string {
	return e.Unwrap().Error()
}

// Unwraps to FileNotFoundFromSearchError.
func (e ConfigFileNotFoundError) Unwrap() error {
	return FileNotFoundFromSearchError(e)
}

// FileNotFoundFromSearchError denotes failing to find a configuration file from a search.
// Wraps ConfigFileNotFoundError.
type FileNotFoundFromSearchError struct {
	locations []string
	name      string
}

func (e FileNotFoundFromSearchError) fileLookup() {}
Repository: spf13/viper
File: errors.go (Go)

Code before:
package viper

import (
	"fmt"
)

/* ConfigFileNotFoundError types */

// For matching on any ConfigFileNotFoundFrom*Error.
type ConfigFileNotFoundError interface {
	Error() string
	Name() string
	Locations() string
}

// ConfigFileNotFoundFromFinderError denotes failing to find a configuration file.
type ConfigFileNotFoundFromFinderError struct {
	name, locations string
}

// Error returns the formatted configuration error.
func (fnfe ConfigFileNotFoundFromFinderError) Error() string {
	message := fmt.Sprintf("Config file %q Not Found", fnfe.name)
	if fnfe.locations != "" {
		message += fmt.Sprintf(" in %q", fnfe.locations)
	}

	return message
}

func (fnfe ConfigFileNotFoundFromFinderError) Name() string {
	return fnfe.name
}

func (fnfe ConfigFileNotFoundFromFinderError) Locations() string {
	return fnfe.locations
}

// ConfigFileNotFoundFromReadError denotes failing to find a specific configuration file.
type ConfigFileNotFoundFromReadError struct {
	name string
}

// Error returns the formatted configuration error.
func (fnfe ConfigFileNotFoundFromReadError) Error() string {
	return fmt.Sprintf("Config file %q Not Found", fnfe.name)
}


Review comment (suggestion):
File %q not found?

Also, since it's possible to pass in a custom finder (i.e. doesn't have to be a config name), it might make sense to return something like `File matching these criteria cannot be found`.

Code after:
package viper

import (
	"fmt"
)

// FileLookupError is returned when Viper cannot resolve a configuration file.
//
// This is meant to be a common interface for all file look-up errors, occurring either because a
// file does not exist or because it cannot find any file matching finder criteria.
type FileLookupError interface {
	error

	fileLookup()
}

// ConfigFileNotFoundError denotes failing to find a configuration file from a search.
//
// Deprecated: This is error wraps [FileNotFoundFromSearchError], which should be used instead.
type ConfigFileNotFoundError struct {
	locations []string
	name      string
}

// Error returns the formatted error.
func (e ConfigFileNotFoundError) Error() string {
	return e.Unwrap().Error()
}

// Unwraps to FileNotFoundFromSearchError.
func (e ConfigFileNotFoundError) Unwrap() error {
	return FileNotFoundFromSearchError(e)
}

// FileNotFoundFromSearchError denotes failing to find a configuration file from a search.
// Wraps ConfigFileNotFoundError.
type FileNotFoundFromSearchError struct {
	locations []string
	name      string
}

func (e FileNotFoundFromSearchError) fileLookup() {}

// Error returns the formatted error.
func (e FileNotFoundFromSearchError) Error() string {
	message := fmt.Sprintf("File %q not found", e.name)

	if len(e.locations) > 0 {
Repository: spf13/viper
File: viper.go (Go)

Code before:
}

// ReadInConfig will discover and load the configuration file from disk
// and key/value stores, searching in one of the defined paths.
func ReadInConfig() error { return v.ReadInConfig() }

func (v *Viper) ReadInConfig() error {
	v.logger.Info("attempting to read in config file")
	filename, err := v.getConfigFile()
	if err != nil {
		return err
	}

	if !slices.Contains(SupportedExts, v.getConfigType()) {
		return UnsupportedConfigError(v.getConfigType())
	}

	v.logger.Debug("reading file", "file", filename)
	exists, err := afero.Exists(v.fs, filename)
	if err != nil {
		return err
	}
	if !exists {
		return ConfigFileNotFoundFromReadError{name: filename}
	}
	file, err := afero.ReadFile(v.fs, filename)
	if err != nil {
		return err
	}
	config := make(map[string]any)

	err = v.unmarshalReader(bytes.NewReader(file), config)
	if err != nil {
		return err
	}

	v.config = config
	return nil
}

// MergeInConfig merges a new configuration with an existing config.
func MergeInConfig() error { return v.MergeInConfig() }

func (v *Viper) MergeInConfig() error {
	v.logger.Info("attempting to merge in config file")
	filename, err := v.getConfigFile()
	if err != nil {
		return err
	}

	if !slices.Contains(SupportedExts, v.getConfigType()) {

Review comment (suggestion):
Can you check if the Afero API returns a distinguishable "not found" error?

If so, the above exists is not necessary.

If not, please add a comment that the above check is necessary because there is no other way to figure out.

Code after:
	path := strings.Split(key, v.keyDelim)
	lastKey := strings.ToLower(path[len(path)-1])
	deepestMap := deepSearch(v.override, path[0:len(path)-1])

	// set innermost value
	deepestMap[lastKey] = value
}

// ReadInConfig will discover and load the configuration file from disk
// and key/value stores, searching in one of the defined paths.
func ReadInConfig() error { return v.ReadInConfig() }

func (v *Viper) ReadInConfig() error {
	v.logger.Info("attempting to read in config file")
	filename, err := v.getConfigFile()
	if err != nil {
		return err
	}

	if !slices.Contains(SupportedExts, v.getConfigType()) {
		return UnsupportedConfigError(v.getConfigType())
	}

	v.logger.Debug("reading file", "file", filename)

	file, err := afero.ReadFile(v.fs, filename)
	if errors.Is(err, fs.ErrNotExist) {
		// The specified config file is missing
		return FileNotFoundError{err: err, path: filename}
	} else if err != nil {
		// We hit some other error from the filesystem that isn't a missing file
		return err
	}

	config := make(map[string]any)

	err = v.unmarshalReader(bytes.NewReader(file), config)
	if err != nil {
		return err
	}

	v.config = config
	return nil
}

// MergeInConfig merges a new configuration with an existing config.
func MergeInConfig() error { return v.MergeInConfig() }

func (v *Viper) MergeInConfig() error {
	v.logger.Info("attempting to merge in config file")
	filename, err := v.getConfigFile()
Repository: spf13/viper
File: errors.go (Go)

Code before:
package viper

import (
	"fmt"
)

/* File look-up errors */

// ConfigFileNotFoundError denotes failing to find a configuration file from a search.
//
// Deprecated: This is wrapped by FileNotFoundFromSearchError, which should be used instead.
type ConfigFileNotFoundError struct {
	name      string
	locations []string
}

// Error returns the formatted error.
func (fnfe ConfigFileNotFoundError) Error() string {
	message := fmt.Sprintf("File %q Not Found", fnfe.name)
	if len(fnfe.locations) != 0 {
		message += fmt.Sprintf(" in %v", fnfe.locations)
	}

	return message
}

// Unwraps to FileNotFoundFromSearchError.
func (fnfe ConfigFileNotFoundError) Unwrap() error {
	return FileNotFoundFromSearchError{err: fnfe}
}

// FileNotFoundFromSearchError denotes failing to find a configuration file from a search.
// Wraps ConfigFileNotFoundError.
type FileNotFoundFromSearchError struct {
	err ConfigFileNotFoundError
}

// Error returns the formatted error.
func (fnfe FileNotFoundFromSearchError) Error() string {
	return fnfe.err.Error()
}

// FileNotFoundError denotes failing to find a specific configuration file.

Review comment (suggestion):
```suggestion
func (e ConfigFileNotFoundError) Error() string {
```

Code after:
package viper

import (
	"fmt"
)

// FileLookupError is returned when Viper cannot resolve a configuration file.
//
// This is meant to be a common interface for all file look-up errors, occurring either because a
// file does not exist or because it cannot find any file matching finder criteria.
type FileLookupError interface {
	error

	fileLookup()
}

// ConfigFileNotFoundError denotes failing to find a configuration file from a search.
//
// Deprecated: This is error wraps [FileNotFoundFromSearchError], which should be used instead.
type ConfigFileNotFoundError struct {
	locations []string
	name      string
}

// Error returns the formatted error.
func (e ConfigFileNotFoundError) Error() string {
	return e.Unwrap().Error()
}

// Unwraps to FileNotFoundFromSearchError.
func (e ConfigFileNotFoundError) Unwrap() error {
	return FileNotFoundFromSearchError(e)
}

// FileNotFoundFromSearchError denotes failing to find a configuration file from a search.
// Wraps ConfigFileNotFoundError.
type FileNotFoundFromSearchError struct {
	locations []string
	name      string
}

func (e FileNotFoundFromSearchError) fileLookup() {}