{"id":"c5db24d314178b23","repo":"spf13/viper","slug":"config-type-could-not-be-determined-for-s","errorCode":null,"errorMessage":"config type could not be determined for %s","messagePattern":"config type could not be determined for (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"viper.go","lineNumber":1755,"sourceCode":"\tif alreadyExists && err == nil {\n\t\treturn ConfigFileAlreadyExistsError(filename)\n\t}\n\treturn v.writeConfig(filename, false)\n}\n\nfunc (v *Viper) writeConfig(filename string, force bool) error {\n\tv.logger.Info(\"attempting to write configuration to file\")\n\n\tvar configType string\n\n\text := filepath.Ext(filename)\n\tif ext != \"\" && ext != filepath.Base(filename) {\n\t\tconfigType = ext[1:]\n\t} else {\n\t\tconfigType = v.configType\n\t}\n\tif configType == \"\" {\n\t\treturn fmt.Errorf(\"config type could not be determined for %s\", filename)\n\t}\n\n\tif !slices.Contains(SupportedExts, configType) {\n\t\treturn UnsupportedConfigError(configType)\n\t}\n\tif v.config == nil {\n\t\tv.config = make(map[string]any)\n\t}\n\tflags := os.O_CREATE | os.O_TRUNC | os.O_WRONLY\n\tif !force {\n\t\tflags |= os.O_EXCL\n\t}\n\tf, err := v.fs.OpenFile(filename, flags, v.configPermissions)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer f.Close()\n","sourceCodeStart":1737,"sourceCodeEnd":1773,"githubUrl":"https://github.com/spf13/viper/blob/528f7416c4b56a4948673984b190bf8713f0c3c4/viper.go#L1737-L1773","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Call v.SetConfigType(\"yaml\") (or json/toml/env) before WriteConfig/WriteConfigAs.","Write to a filename with a recognized extension (e.g. 'app.yaml') so the type is inferred from the extension.","For dotfiles or extensionless names, SetConfigType is mandatory — there is no fallback."],"exampleFix":"// before\nv := New()\nv.SetConfigName(\"app\")\n_ = v.WriteConfigAs(\"/etc/myapp/config\") // -> config type could not be determined for /etc/myapp/config\n\n// after\nv.SetConfigType(\"yaml\")\n_ = v.WriteConfigAs(\"/etc/myapp/config\")\n// or: _ = v.WriteConfigAs(\"/etc/myapp/config.yaml\")","handlingStrategy":"validation","validationCode":"// Before WriteConfig/WriteConfigAs, ensure a type is resolvable.\nfunc ensureWriteType(v *viper.Viper, filename string) error {\n    ext := filepath.Ext(filename)\n    hasExt := ext != \"\" && ext != filepath.Base(filename)\n    if hasExt { return nil }\n    if v.GetConfigType() != \"\" { return nil }\n    return errors.New(\"no config type: call SetConfigType or use an extension\")\n}\n\nif err := ensureWriteType(v, \"/etc/myapp/config\"); err != nil {\n    v.SetConfigType(\"yaml\")\n}\nv.WriteConfigAs(\"/etc/myapp/config\")","typeGuard":null,"tryCatchPattern":"if err := v.WriteConfigAs(path); err != nil {\n    if strings.Contains(err.Error(), \"config type could not be determined\") {\n        v.SetConfigType(\"yaml\")\n        err = v.WriteConfigAs(path)\n    }\n}","preventionTips":["Always write config files with a recognized extension.","If you must use an extensionless/dotfile name, call SetConfigType unconditionally.","Remember filepath.Ext('.myapp') returns '' — dotfiles look extensionless to Viper."],"tags":["config-write","type","extension"],"analyzedSha":"528f7416c4b56a4948673984b190bf8713f0c3c4","analyzedAt":"2026-08-04T21:46:12.352Z","schemaVersion":2}