{"record":{"id":"4c3439947f603633","repo":"air-verse/air","slug":"failed-to-parse-s-w","errorCode":null,"errorMessage":"failed to parse %s: %w","messagePattern":"failed to parse (.+?): %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"runner/config.go","lineNumber":390,"sourceCode":"\t\treturn \"\", fmt.Errorf(\"failed to write to %s: %w\", dftTOML, err)\n\t}\n\n\treturn dftTOML, nil\n}\n\n// defaultPathConfig loads `.air.toml` or `.config/air.toml` when present.\n// The bool is true when a config file was loaded, false when defaults are returned.\nfunc defaultPathConfig() (*Config, bool, error) {\n\t// when path is blank, first find `.air.toml` in `air_wd` and current working directory or .config/air.toml, if not found, use defaults\n\tfor _, name := range []string{dftTOML, cfgTOML} {\n\t\tcfg, err := readConfByName(name)\n\t\tif err == nil {\n\t\t\treturn cfg, true, nil\n\t\t}\n\t\t// If the config file exists but failed to parse, report the error\n\t\t// Only use defaults if no config file exists\n\t\tif !os.IsNotExist(err) {\n\t\t\treturn nil, false, fmt.Errorf(\"failed to parse %s: %w\", name, err)\n\t\t}\n\t}\n\n\tdftCfg := defaultConfig()\n\treturn &dftCfg, false, nil\n}\n\nfunc readConfByName(name string) (*Config, error) {\n\tvar path string\n\tif wd := os.Getenv(airWd); wd != \"\" {\n\t\tpath = filepath.Join(wd, name)\n\t} else {\n\t\twd, err := os.Getwd()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tpath = filepath.Join(wd, name)\n\t}","sourceCodeStart":372,"sourceCodeEnd":408,"githubUrl":"https://github.com/air-verse/air/blob/71ea1dee05248122ed22b5870c7fb20a90d80ddd/runner/config.go#L372-L408","documentation":"Air wraps the underlying TOML decode failure when parsing a user-supplied config file. If the config file exists but cannot be parsed (invalid TOML syntax, wrong types), air returns this wrapped error instead of silently falling back to defaults. Defaults are only used when no config file exists.","triggerScenarios":"Running `air` (or air's config-loading path via parseConfig) with a .air.toml/.air.conf file that exists but contains malformed TOML or a field with an incompatible type; parseFile decodes it with the toml library and the decode error is wrapped here.","commonSituations":"Hand-edited config with a missing quote, unbalanced bracket, or tab/indentation mistake; copying a config from an older air version with renamed/retyped fields; accidentally writing JSON or YAML into a .toml file.","solutions":["Read the wrapped `%w` cause to find the exact TOML line/column and fix the syntax","Validate the file with a TOML linter (e.g. `tomlcheck .air.toml` or taplo)","If unsure, regenerate a known-good config with `air init` and re-apply your customizations","Ensure the file extension matches its content (.toml for TOML)"],"exampleFix":"// before (.air.toml)\n[build]\nbin = \"tmp/main  // unterminated string\n// after\n[build]\nbin = \"tmp/main\"","handlingStrategy":"validation","validationCode":"// before running air\nfunc configValid(path string) error {\n\tif _, err := os.Stat(path); os.IsNotExist(err) {\n\t\treturn nil // air will use defaults\n\t}\n\tvar cfg map[string]any\n\t_, err := toml.DecodeFile(path, &cfg)\n\treturn err\n}","typeGuard":null,"tryCatchPattern":"if err := runAir(); err != nil {\n\tvar perr *toml.ParseError\n\tif errors.As(err, &perr) {\n\t\tlog.Fatalf(\"fix config syntax: %v\", perr) // points at line/col\n\t}\n\tlog.Fatal(err)\n}","preventionTips":["Validate .air.toml with a TOML linter in CI or a pre-commit hook","Regenerate config with `air init` when upgrading air versions","Keep one canonical config and symlink instead of hand-copying","Avoid mixing JSON/YAML into .toml files"],"tags":["config","toml","parsing"],"backgroundTag":"config-file-parse-error","analyzedSha":"71ea1dee05248122ed22b5870c7fb20a90d80ddd","analyzedAt":"2026-08-31T20:27:54.676Z","schemaVersion":2},"datasetVersion":"2026-09-01T03:17:15.561Z"}