fatedier/frp · error

toml: line %d, column %d: %s

Error message

toml: line %d, column %d: %s

What it means

When a TOML frp config file fails to decode, formatTOMLError converts the pelletier/go-toml DecodeError into a message with 1-indexed line and column of the offending syntax plus the parser's description. This gives precise locations for structural TOML errors (bad brackets, duplicate keys, invalid values).

Source

Thrown at pkg/config/load.go:224

	// Handle YAML content
	if strict {
		// In strict mode, always use our custom handler to support YAML merge
		if err := parseYAMLWithDotFieldsHandling(b, c); err != nil {
			return enhanceDecodeError(err, originalBytes, !parsedFromTOML)
		}
		return nil
	}
	// Non-strict mode, parse normally
	return yaml.Unmarshal(b, c)
}

// formatTOMLError extracts line/column information from TOML decode errors.
func formatTOMLError(err error) error {
	var decErr *toml.DecodeError
	if errors.As(err, &decErr) {
		row, col := decErr.Position()
		return fmt.Errorf("toml: line %d, column %d: %s", row, col, decErr.Error())
	}
	var strictErr *toml.StrictMissingError
	if errors.As(err, &strictErr) {
		return strictErr
	}
	return err
}

// enhanceDecodeError tries to add field path and line number information to JSON/YAML decode errors.
func enhanceDecodeError(err error, originalContent []byte, includeLine bool) error {
	var typeErr *json.UnmarshalTypeError
	if errors.As(err, &typeErr) && typeErr.Field != "" {
		if includeLine {
			line := findFieldLineInContent(originalContent, typeErr.Field)
			if line > 0 {
				return fmt.Errorf("line %d: field \"%s\": cannot unmarshal %s into %s", line, typeErr.Field, typeErr.Value, typeErr.Type)
			}
		}

View on GitHub (pinned to 6c8a8d0a97)

Solutions

  1. Go to the reported line:column and fix the syntax pointed at
  2. Run a TOML linter (taplo, toml-validate) over the file
  3. If the file is actually YAML/JSON, rename it with the proper extension so frp picks the right parser

Example fix

# before (line 12 reported)
[[proxies]
name = "web"

# after
[[proxies]]
name = "web"
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-validate TOML before loading
if err := toml.Unmarshal(raw, map[string]any{}); err != nil { return fmt.Errorf("toml pre-check: %w", err) }

Try / catch

if err := config.LoadConfigureFromFile(path, &cfg, strict); err != nil { var decErr *toml.DecodeError; if errors.As(err, &decErr) { r, c := decErr.Position(); /* point editor at r:c */ } }

Prevention

When it happens

Trigger: Loading a .toml frpc/frps config whose syntax is invalid: unclosed table [[proxies]], duplicate key in one table, wrong scalar syntax, stray characters. The TOML unmarshal path in LoadConfigureFromFile routes through this formatter.

Common situations: Hand-editing TOML configs and losing a bracket; snippets pasted from YAML docs into TOML files (colons/indentation); TOML files written by scripts with unescaped strings.

Related errors


AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15). Data as JSON: /api/errors/cf8876aa022b03e0. Report an issue: GitHub.