spf13/viper · error

encoder not found for this format

Error message

encoder not found for this format

What it means

Returned by DefaultCodecRegistry.Encoder (encoding.go:132-138) when r.codec(format) finds no match. The built-in registry only ships codecs for yaml/yml, json, toml, and dotenv/env (encoding.go:166-178); any other format string yields this error. It surfaces through marshalWriter (viper.go:1818) whenever Viper serializes config to a file or io.Writer.

Source

Thrown at encoding.go:135

// Format is case-insensitive.
func (r *DefaultCodecRegistry) RegisterCodec(format string, codec Codec) error {
	r.init()

	r.mu.Lock()
	defer r.mu.Unlock()

	r.codecs[strings.ToLower(format)] = codec

	return nil
}

// Encoder implements the [EncoderRegistry] interface.
//
// Format is case-insensitive.
func (r *DefaultCodecRegistry) Encoder(format string) (Encoder, error) {
	encoder, ok := r.codec(format)
	if !ok {
		return nil, errors.New("encoder not found for this format")
	}

	return encoder, nil
}

// Decoder implements the [DecoderRegistry] interface.
//
// Format is case-insensitive.
func (r *DefaultCodecRegistry) Decoder(format string) (Decoder, error) {
	decoder, ok := r.codec(format)
	if !ok {
		return nil, errors.New("decoder not found for this format")
	}

	return decoder, nil
}

func (r *DefaultCodecRegistry) codec(format string) (Codec, bool) {

View on GitHub (pinned to 528f7416c4)

Solutions

  1. Write to a format with a built-in codec: use an extension of json, yaml/yml, toml, or dotenv/env (SetConfigType or filename ext).
  2. If you must write hcl/ini/properties/etc., construct a DefaultCodecRegistry, call RegisterCodec("hcl", myCodec), and pass it via v := NewWithOptions(WithEncoderRegistry(r)) or WithCodecRegistry(r).
  3. Verify the format is actually registered before writing: guard with slices.Contains([]string{"json","yaml","yml","toml","env","dotenv"}, configType).

Example fix

// before
v.SetConfigName("app")
v.SetConfigType("hcl")
v.AddConfigPath("/etc/myapp")
_ = v.WriteConfig() // -> ConfigMarshalError: encoder not found for this format

// after (option A: use built-in codec)
v.SetConfigType("yaml")
_ = v.WriteConfig()

// after (option B: register an HCL codec)
r := NewCodecRegistry()
_ = r.RegisterCodec("hcl", myHCLCodec{})
v := NewWithOptions(WithCodecRegistry(r))
Defensive patterns

Strategy: validation

Validate before calling

// Confirm a built-in codec exists before writing.
var hasBuiltinEncoder = map[string]bool{"json": true, "yaml": true, "yml": true, "toml": true, "env": true, "dotenv": true}
func canEncode(format string) bool { return hasBuiltinEncoder[strings.ToLower(format)] }

// usage
cfgType := strings.ToLower(v.GetConfigType())
if cfgType == "" { cfgType = strings.TrimPrefix(filepath.Ext(outPath), ".") }
if !canEncode(cfgType) {
    // register a codec via NewCodecRegistry().RegisterCodec(cfgType, codec), or switch extension
}

Try / catch

if err := v.WriteConfig(); err != nil {
    var marshalErr viper.ConfigMarshalError
    if errors.As(err, &marshalErr) {
        // encoder missing -> register a codec or change format
    }
}

Prevention

When it happens

Trigger: Calling WriteConfig, WriteConfigAs, SafeWriteConfig, or WriteConfigTo when the resolved configType (filename extension or SetConfigType value) is one of the SupportedExts entries that has no built-in codec in this version — 'ini', 'hcl', 'tfvars', 'properties', 'props', 'prop' — or any custom/unregistered format string. marshalWriter calls v.encoderRegistry.Encoder(configType) and wraps the result in ConfigMarshalError.

Common situations: Upgrading from an older Viper that bundled HCL/INI/properties encoders; switching a YAML app to write .hcl/.ini; passing a custom registry via WithEncoderRegistry that forgot RegisterCodec for the format you write; typo in the file extension.

Related errors


AI-assisted analysis of spf13/viper@528f7416c4 (2026-08-04). Data as JSON: /data/errors/fa82535d1b3f2a24.json. Report an issue: GitHub.