Skip to content

[confmap] Embedded structs fail to unmarshal #12709

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
bogdandrutu opened this issue Mar 23, 2025 · 5 comments
Open

[confmap] Embedded structs fail to unmarshal #12709

bogdandrutu opened this issue Mar 23, 2025 · 5 comments
Labels
bug Something isn't working

Comments

@bogdandrutu
Copy link
Member

bogdandrutu commented Mar 23, 2025

Component(s)

confmap

What happened?

type Config struct {
	FooConfig `mapstructure:"foo"`
	Encoding  string  `mapstructure:"encoding"`
}

type FooConfig struct {
   MyString "my_foo_string"
} 

Now, if we define the "Unmarshal" on "FooConfig" we will get an error that encoding is not defined. This is a problem that will stop development for FooConfig.

Collector version

v0.122.0

@bogdandrutu bogdandrutu added the bug Something isn't working label Mar 23, 2025
Copy link
Contributor

Pinging code owners:

See Adding Labels via Comments if you do not have permissions to add labels yourself.

@bogdandrutu
Copy link
Member Author

Probably the easiest solution is to disallow "embedded" structs that are not "squashed", but would be good for someone to think about this.

github-merge-queue bot pushed a commit that referenced this issue Mar 24, 2025
This PR:
* Helps with
#12709,
to avoid the situation where we need to add Unmarshal for a struct and
if used as embedded will not work.
* Helps with avoiding name conflicts between variables. Will allow for
example to have a "Timeout" member in both QueueConfig and ClientConfig,
even though that was a valid YAML config since `QueueConfig` is under
"seding_queue".
* This is a breaking change only if devs are created manually the OTLP
configs which should be very rare, and unfortunately this is hard to do
using deprecation steps.

Signed-off-by: Bogdan Drutu <[email protected]>
@mattsains
Copy link
Contributor

I ran into this issue myself when trying to upgrade to 0.123.0

It seems that using an embedded struct also brings in all of its implementations, so Config ends up having the unmarshaler of FooConfig.

This was surprising to me as someone who isn't a go expert.

@songy23
Copy link
Member

songy23 commented Apr 9, 2025

Not sure if it's the same issue but I found the error message quite misleading:

Consider this simple test

type MyExpCfg struct {
	Timeout time.Duration `mapstructure:"timeout"`
	QueueConfig `mapstructure:",squash"`
}

func TestUnmarshalConfig(t *testing.T) {
	cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml"))
	require.NoError(t, err)
	sub, err := cm.Sub(component.MustNewID("my_exp").String())
	require.NoError(t, err)
	got := MyExpCfg{}
	require.NoError(t, sub.Unmarshal(&got))
	assert.NoError(t, xconfmap.Validate(got))
}

Test config

my_exp:
  timeout: 10s
  queue_size: 100

This used to work fine until v0.123.0. In v0.123.0 the above returns an error:

decoding failed due to the following error(s):
error decoding '': decoding failed due to the following error(s):
'' has invalid keys: timeout

...but the issue has nothing to do with timeout, the fix is instead to move QueueConfig to a dedicated sub-section like

type MyExpCfg struct {
	Timeout time.Duration `mapstructure:"timeout"`
	QueueConfig `mapstructure:"sending_queue"`
}

This should be an API breaking change, though I cannot find any reference in the changelog

@songy23
Copy link
Member

songy23 commented Apr 9, 2025

Probably the easiest solution is to disallow "embedded" structs that are not "squashed"

In the example above if you squash the embedded struct, it leads to an unmarshal error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants