From 1a60ee6d0f90c63433981336d297536f4d409b2c Mon Sep 17 00:00:00 2001 From: Varun Chawla Date: Wed, 11 Mar 2026 21:25:09 -0700 Subject: [PATCH 1/2] fix: remove dropped formats (HCL, INI, Java Properties) from SupportedExts Since v1.20, HCL, Java Properties, and INI were removed from core encoding, but SupportedExts still listed them. This caused misleading file searches (Viper looked for .hcl/.ini/.properties files it could not decode) and confusing errors where format validation passed but codec lookup failed with a generic ConfigParseError. Update SupportedExts to only include formats with built-in codecs (JSON, TOML, YAML, Dotenv). Users who register custom codecs for the removed formats via WithCodecRegistry can append to SupportedExts. Also update README to reflect the current supported formats and link to the upgrade guide for the removed formats. Fixes #2092 --- README.md | 9 ++++++--- viper.go | 6 ++++-- viper_test.go | 2 +- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index f48ebb790..41caa1666 100644 --- a/README.md +++ b/README.md @@ -90,9 +90,12 @@ Viper requires minimal configuration to load config files. Viper currently suppo * JSON * TOML * YAML -* INI -* envfile -* Java Propeties +* Dotenv + +> **NOTE (since v1.20):** HCL, Java Properties, and INI were removed from core to reduce +> third-party dependencies. You can still use them by registering codecs from +> [github.com/go-viper/encoding](https://github.com/go-viper/encoding). +> See the [upgrade guide](UPGRADE.md#breaking-hcl-java-properties-ini-removed-from-core) for details. A single Viper instance only supports a single configuration file, but multiple paths may be searched for one. diff --git a/viper.go b/viper.go index 2d5158cbd..fd74734f2 100644 --- a/viper.go +++ b/viper.go @@ -259,13 +259,15 @@ func SetOptions(opts ...Option) { // can use it in their testing as well. func Reset() { v = New() - SupportedExts = []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl", "tfvars", "dotenv", "env", "ini"} + SupportedExts = []string{"json", "toml", "yaml", "yml", "dotenv", "env"} resetRemote() } // SupportedExts are universally supported extensions. -var SupportedExts = []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl", "tfvars", "dotenv", "env", "ini"} +// Since v1.20, HCL, Java Properties, and INI were removed from core. +// To use them, register a custom codec via [WithCodecRegistry] and append to this list. +var SupportedExts = []string{"json", "toml", "yaml", "yml", "dotenv", "env"} // OnConfigChange sets the event handler that is called when a config file changes. func OnConfigChange(run func(in fsnotify.Event)) { v.OnConfigChange(run) } diff --git a/viper_test.go b/viper_test.go index 8b0232aee..9924112d0 100644 --- a/viper_test.go +++ b/viper_test.go @@ -1825,7 +1825,7 @@ func TestWriteConfig(t *testing.T) { "json with file extension and mismatch type": { configName: "c", inConfigType: "json", - outConfigType: "hcl", + outConfigType: "toml", fileName: "c.json", input: jsonExample, expectedContent: jsonWriteExpected, From 2b35e1792b28f1d71fac4ac0c812bc277c4baeab Mon Sep 17 00:00:00 2001 From: Varun Chawla Date: Wed, 11 Mar 2026 21:25:09 -0700 Subject: [PATCH 2/2] fix: stabilize TestWatchFile on Windows On Windows, fsnotify may deliver the write event before the file content is fully flushed, causing ReadInConfig to read stale data. Replace the direct equality assertion with assert.Eventually to poll for the expected value, giving the watcher time to pick up the final content. --- viper_test.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/viper_test.go b/viper_test.go index 9924112d0..21b151d17 100644 --- a/viper_test.go +++ b/viper_test.go @@ -2462,7 +2462,12 @@ func TestWatchFile(t *testing.T) { wg.Wait() // then the config value should have changed require.NoError(t, err) - assert.Equal(t, "baz", v.Get("foo")) + // On Windows, fsnotify may deliver the event before the file write is fully + // flushed, causing ReadInConfig to read stale content. Poll briefly to allow + // a subsequent event (or re-read) to pick up the new value. + assert.Eventually(t, func() bool { + return v.Get("foo") == "baz" + }, 5*time.Second, 10*time.Millisecond, "expected foo to be \"baz\"") }) t.Run("link to real file changed (à la Kubernetes)", func(t *testing.T) {