spf13/viper · error
decoder not found for this format
Error message
decoder not found for this format
What it means
Returned by DefaultCodecRegistry.Decoder (encoding.go:144-150) when r.codec(format) finds no match. Same codec table as the encoder: only yaml/yml, json, toml, dotenv/env are built in. It surfaces through unmarshalReader (viper.go:1800) wrapped as ConfigParseError whenever Viper reads/parses a config stream.
Source
Thrown at encoding.go:147
// 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) {
r.mu.Lock()
defer r.mu.Unlock()
format = strings.ToLower(format)
if r.codecs != nil {
codec, ok := r.codecs[format]
if ok {
return codec, true
}
}
View on GitHub (pinned to 528f7416c4)
Solutions
- Convert the config to a built-in format (json/yaml/toml/env) or read from one.
- Register a decoder for the format: r := NewCodecRegistry(); r.RegisterCodec("ini", iniCodec{}); v := NewWithOptions(WithDecoderRegistry(r)).
- Double-check that SetConfigType matches an actually-registered codec, not merely an entry in SupportedExts (which lists more formats than the default registry supports).
Example fix
// before
v.SetConfigType("ini")
_ = v.ReadConfig(bytes.NewReader(data)) // -> ConfigParseError: decoder not found for this format
// after
r := NewCodecRegistry()
_ = r.RegisterCodec("ini", myIniCodec{})
v := NewWithOptions(WithDecoderRegistry(r))
v.SetConfigType("ini")
_ = v.ReadConfig(bytes.NewReader(data)) Defensive patterns
Strategy: validation
Validate before calling
var hasBuiltinDecoder = map[string]bool{"json": true, "yaml": true, "yml": true, "toml": true, "env": true, "dotenv": true}
func canDecode(format string) bool { return hasBuiltinDecoder[strings.ToLower(format)] }
// usage before ReadConfig
cfgType := strings.ToLower(v.GetConfigType())
if cfgType == "" { cfgType = strings.TrimPrefix(filepath.Ext(configPath), ".") }
if !canDecode(cfgType) {
// register a decoder or convert the source to a built-in format
} Try / catch
if err := v.ReadConfig(r); err != nil {
var parseErr viper.ConfigParseError
if errors.As(err, &parseErr) && strings.Contains(parseErr.Error(), "decoder not found") {
// format lacks a registered decoder; register one or change SetConfigType
}
} Prevention
- If you read .ini/.hcl/.properties, register a codec for it explicitly at startup.
- Standardize config files on json/yaml/toml to stay within built-in codec coverage.
- Add a smoke test that loads each bundled example config file.
When it happens
Trigger: Calling ReadConfig, ReadConfigAs, WatchConfig (on change), or unmarshaling a remote/env source whose getConfigType() resolves to a format with no built-in decoder — 'ini', 'hcl', 'tfvars', 'properties', 'props', 'prop' — or a custom format with no codec registered via WithDecoderRegistry.
Common situations: Reading a legacy .ini/.hcl/.properties config file after a Viper upgrade that dropped the bundled parser; remote KV store (consul/etcd) with SetConfigType("hcl"); custom decoder registry missing RegisterCodec for the format you read.
Related errors
- encoder not found for this format
- cannot decode configuration: unable to determine config type
- failed to read configuration from input: %w
AI-assisted analysis of spf13/viper@528f7416c4 (2026-08-04).
Data as JSON: /data/errors/954661f2785aa203.json.
Report an issue: GitHub.