viper: 1.18.0 Unmarshal() Breaking Our Tests With: '' expected a map, got 'interface'
Preflight Checklist
- I have searched the issue tracker for an issue that matches the one I want to file, without success.
- I am not looking for support or already pursued the available support channels without success.
- I have checked the troubleshooting guide for my problem, without success.
Viper Version
1.18.0
Go Version
1.21.5
Config Source
Manual set
Format
Other (specify below)
Repl.it link
No response
Code reproducing the issue
No response
Expected Behavior
For now, due to the urgency of this new release having come out only yesterday and limited time (until maybe this weekend?), I can just say that our unit tests (for two modules, within a package we have to wrap/provide common Golang functions) have been running fine for awhile, and with this v1.18.0 release we’re getting these errors from Viper.Unmarshal().
Actual Behavior
Sample error:
config_test.go:146:
Error Trace: /Users/c/go/src/github.com/namely/go-common/config/config_test.go:146
Error: Received unexpected error:
Viper.Unmarshal returned: '' expected a map, got 'interface'
Test: TestConfigTestSuite/TestBind
Steps To Reproduce
No response
Additional Information
I checked the release notes and didn’t see anything obvious, but the code diffs between 1.17.0 and 1.18.0 do show changes in the decoding code that seems to be involved here.
I’m hoping this limited (information-poor) Issue submission might help someone quickly figure out what’s wrong, if anything is indeed wrong with the new release (versus, say, a latent bug in our code, or at least test code).
If not, I’ll endeavor to reduce our layers of wrapping to a simple test case showing the issue, and perhaps “get lucky”, find the bug, and submit a fix as well.
About this issue
- Original URL
- State: open
- Created 7 months ago
- Reactions: 7
- Comments: 29 (8 by maintainers)
@krakowski thanks for the feedback.
How about this: Let’s release 1.18.2 with the build flag solution so that people can go back to the original functionality ASAP.
Then we can tag 1.19 with a runtime version. I’d like to sleep on the API though.
I was able to work around this in our code by changing from:
To:
The
dstvariable there is of typeinterface{}.me too
@sagikazarmark Here’s a repro for the error:
I used to pass a pointer to the global config struct and indirected that once more when calling Viper. Seems that is unnecessary. Passing to
viper.UnmarshalExactby value should be ok since a copy of theconfpointer would still point to the sameglobalConfig. However- that worked before.globalConfiglooks like this:A couple thoughts:
I have a very rudimentary quick fix in https://github.com/spf13/viper/pull/1707. If you could give that a try, that would be great.
It would also be great to understand if there are other cases where mapstructure fails.
The
'' expected a map, got 'interface'seems strange to me, I’m not sure how to replicate it and how it would have worked before.Have also been bitten by this, but in my case we’re not passing a pointer to a pointer, but rather a generic type:
The actual type we pass in to this is a plain struct.
I had a similar issue which I think is due to the additional step when unmarshalling as introduced in #1429 which tries to decode the provided
interface{}into amapusing mapstructure’s decode which later on fails here when trying to decode the data (i.e. the inputinterface{}tovali.e. the output value which is themap. The failure happens because the inputinterface{}'s kind can only be one of the supported types of the switch statement and a pointer is not supported.Fwiw, I fixed this by ensuring that I just pass a pointer to
Unmarshal(and not a pointer to a pointer or something similar).We’re seeing the same here.