spf13/viper · error

config type could not be determined for %s

Error message

config type could not be determined for %s

What it means

Returned by writeConfig (viper.go:1743-1756) when the derived configType is empty. configType comes from the filename extension (if it has one and is not the whole basename), otherwise from v.configType (set via SetConfigType). If both are empty, Viper cannot pick an encoder.

Source

Thrown at viper.go:1755

	if alreadyExists && err == nil {
		return ConfigFileAlreadyExistsError(filename)
	}
	return v.writeConfig(filename, false)
}

func (v *Viper) writeConfig(filename string, force bool) error {
	v.logger.Info("attempting to write configuration to file")

	var configType string

	ext := filepath.Ext(filename)
	if ext != "" && ext != filepath.Base(filename) {
		configType = ext[1:]
	} else {
		configType = v.configType
	}
	if configType == "" {
		return fmt.Errorf("config type could not be determined for %s", filename)
	}

	if !slices.Contains(SupportedExts, configType) {
		return UnsupportedConfigError(configType)
	}
	if v.config == nil {
		v.config = make(map[string]any)
	}
	flags := os.O_CREATE | os.O_TRUNC | os.O_WRONLY
	if !force {
		flags |= os.O_EXCL
	}
	f, err := v.fs.OpenFile(filename, flags, v.configPermissions)
	if err != nil {
		return err
	}
	defer f.Close()

View on GitHub (pinned to 528f7416c4)

Solutions

  1. Call v.SetConfigType("yaml") (or json/toml/env) before WriteConfig/WriteConfigAs.
  2. Write to a filename with a recognized extension (e.g. 'app.yaml') so the type is inferred from the extension.
  3. For dotfiles or extensionless names, SetConfigType is mandatory — there is no fallback.

Example fix

// before
v := New()
v.SetConfigName("app")
_ = v.WriteConfigAs("/etc/myapp/config") // -> config type could not be determined for /etc/myapp/config

// after
v.SetConfigType("yaml")
_ = v.WriteConfigAs("/etc/myapp/config")
// or: _ = v.WriteConfigAs("/etc/myapp/config.yaml")
Defensive patterns

Strategy: validation

Validate before calling

// Before WriteConfig/WriteConfigAs, ensure a type is resolvable.
func ensureWriteType(v *viper.Viper, filename string) error {
    ext := filepath.Ext(filename)
    hasExt := ext != "" && ext != filepath.Base(filename)
    if hasExt { return nil }
    if v.GetConfigType() != "" { return nil }
    return errors.New("no config type: call SetConfigType or use an extension")
}

if err := ensureWriteType(v, "/etc/myapp/config"); err != nil {
    v.SetConfigType("yaml")
}
v.WriteConfigAs("/etc/myapp/config")

Try / catch

if err := v.WriteConfigAs(path); err != nil {
    if strings.Contains(err.Error(), "config type could not be determined") {
        v.SetConfigType("yaml")
        err = v.WriteConfigAs(path)
    }
}

Prevention

When it happens

Trigger: Calling v.WriteConfigAs("configfile") with a path that has no extension and no prior SetConfigType; v.WriteConfig() where the resolved config file is extensionless and SetConfigType was never called.

Common situations: Writing generated config to an extensionless path (e.g. /run/myapp/current); renaming to a dotfile like '.myapp' (filepath.Ext returns ''); building a config bootstrapper that picks an arbitrary filename.

Related errors


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