hyperledger/fabric · error

supplied output argument must be a pointer to a struct, but

Error message

supplied output argument must be a pointer to a struct, but it is pointer to something else

What it means

After confirming output is a pointer, EnhancedExactUnmarshal checks that the pointed-to element type is a struct, since it builds leaf keys from the struct's fields via getKeysRecursively. A pointer to anything else (map, slice, string) cannot be reflected into the exact-key unmarshal machinery, so this error is returned.

Source

Thrown at common/viperutil/config_util.go:385

	err := mapstructure.WeakDecode(data, config)
	if err != nil {
		return nil, errors.Wrap(err, "could not decode bccsp type")
	}

	return config, nil
}

// EnhancedExactUnmarshal is intended to unmarshal a config file into a structure
// producing error when extraneous variables are introduced and supporting
// the time.Duration type
func (c *ConfigParser) EnhancedExactUnmarshal(output any) error {
	oType := reflect.TypeOf(output)
	if oType.Kind() != reflect.Pointer {
		return errors.Errorf("supplied output argument must be a pointer to a struct but is not pointer")
	}
	eType := oType.Elem()
	if eType.Kind() != reflect.Struct {
		return errors.Errorf("supplied output argument must be a pointer to a struct, but it is pointer to something else")
	}

	baseKeys := c.config
	leafKeys := getKeysRecursively("", c.getFromEnv, baseKeys, eType)

	logger.Debugf("%+v", leafKeys)
	config := &mapstructure.DecoderConfig{
		ErrorUnused:      true,
		Metadata:         nil,
		Result:           output,
		WeaklyTypedInput: true,
		DecodeHook: mapstructure.ComposeDecodeHookFunc(
			bccspHook,
			mapstructure.StringToTimeDurationHookFunc(),
			customDecodeHook,
			byteSizeDecodeHook,
			stringFromFileDecodeHook,
			pemBlocksFromFileDecodeHook,

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Define a target struct matching your config keys and pass its pointer.
  2. If you need dynamic maps, use plain viper.Get/mapstructure decode instead of EnhancedExactUnmarshal.
  3. If using generics/any, assert the concrete struct pointer type before calling.

Example fix

// before
out := map[string]any{}
parser.EnhancedExactUnmarshal(&out)
// after
type MyConfig struct { Peer string }
out := MyConfig{}
parser.EnhancedExactUnmarshal(&out)
Defensive patterns

Strategy: type-guard

Validate before calling

t := reflect.TypeOf(out)
if t == nil || t.Kind() != reflect.Pointer || t.Elem().Kind() != reflect.Struct {
    return errors.New("output must be a pointer to a struct")
}

Type guard

func isStructPointer(v any) bool {
    t := reflect.TypeOf(v)
    return t != nil && t.Kind() == reflect.Pointer && t.Elem().Kind() == reflect.Struct
}

Try / catch

if !isStructPointer(&out) { /* restructure */ }
if err := parser.EnhancedExactUnmarshal(&out); err != nil {
    return fmt.Errorf("config unmarshal failed: %w", err)
}

Prevention

When it happens

Trigger: Calling parser.EnhancedExactUnmarshal(&someMap) or &someSlice; passing **struct double pointers may also fail the kind checks depending on reflection handling.

Common situations: Developers try to unmarshal into map[string]any to 'just get everything', but EnhancedExactUnmarshal deliberately targets structs; generic wrapper functions using any erase the struct type.

Related errors


AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04). Data as JSON: /api/errors/3b003debff74d9b5. Report an issue: GitHub.