diff --git a/cmd/frostfs-node/config/config.go b/cmd/frostfs-node/config/config.go
index cf8ca0a4d..e1b142aed 100644
--- a/cmd/frostfs-node/config/config.go
+++ b/cmd/frostfs-node/config/config.go
@@ -35,7 +35,11 @@ type Prm struct{}
 // configuration values are read from it.
 // Otherwise, Config is a degenerate tree.
 func New(_ Prm, opts ...configViper.Option) *Config {
-	v, o := configViper.CreateViper(opts...)
+	v, o, err := configViper.CreateViper(opts...)
+
+	if err != nil {
+		panic(err)
+	}
 
 	return &Config{
 		v:    v,
diff --git a/cmd/internal/common/config/viper.go b/cmd/internal/common/config/viper.go
index 63e8ba05c..b0af9ae28 100644
--- a/cmd/internal/common/config/viper.go
+++ b/cmd/internal/common/config/viper.go
@@ -15,7 +15,7 @@ const (
 	EnvSeparator = "_"
 )
 
-func CreateViper(opts ...Option) (*viper.Viper, *Opts) {
+func CreateViper(opts ...Option) (*viper.Viper, *Opts, error) {
 	v := viper.New()
 
 	o := DefaultOpts()
@@ -34,17 +34,17 @@ func CreateViper(opts ...Option) (*viper.Viper, *Opts) {
 
 		err := v.ReadInConfig()
 		if err != nil {
-			panic(fmt.Errorf("failed to read config: %w", err))
+			return nil, nil, fmt.Errorf("failed to read config: %w", err)
 		}
 	}
 
 	if o.ConfigDir != "" {
 		if err := config.ReadConfigDir(v, o.ConfigDir); err != nil {
-			panic(fmt.Errorf("failed to read config dir: %w", err))
+			return nil, nil, fmt.Errorf("failed to read config dir: %w", err)
 		}
 	}
 
-	return v, o
+	return v, o, nil
 }
 
 func ReloadViper(v *viper.Viper, o Opts) error {