From b7435967b04bd0d4f9261a91af4c31f91006ab80 Mon Sep 17 00:00:00 2001 From: fatedier Date: Wed, 4 Mar 2026 20:53:22 +0800 Subject: [PATCH] pkg/config: fix line numbers shown incorrectly for TOML type mismatch errors (#5195) --- pkg/config/load.go | 24 ++++++++++++++++-------- pkg/config/load_test.go | 6 ++++-- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/pkg/config/load.go b/pkg/config/load.go index dc1de0af..38634fc5 100644 --- a/pkg/config/load.go +++ b/pkg/config/load.go @@ -180,24 +180,26 @@ func LoadConfigure(b []byte, c any, strict bool, formats ...string) error { } originalBytes := b + parsedFromTOML := false var tomlObj any tomlErr := toml.Unmarshal(b, &tomlObj) if tomlErr == nil { + parsedFromTOML = true var err error b, err = jsonx.Marshal(&tomlObj) if err != nil { return err } } else if format == "toml" { - // File is known to be TOML but has syntax errors — report with line/column info. + // File is known to be TOML but has syntax errors. return formatTOMLError(tomlErr) } // If the buffer smells like JSON (first non-whitespace character is '{'), unmarshal as JSON directly. if yaml.IsJSONBuffer(b) { if err := decodeJSONContent(b, c, strict); err != nil { - return enhanceDecodeError(err, originalBytes) + return enhanceDecodeError(err, originalBytes, !parsedFromTOML) } return nil } @@ -206,7 +208,7 @@ func LoadConfigure(b []byte, c any, strict bool, formats ...string) error { 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) + return enhanceDecodeError(err, originalBytes, !parsedFromTOML) } return nil } @@ -223,18 +225,20 @@ func formatTOMLError(err error) error { } var strictErr *toml.StrictMissingError if errors.As(err, &strictErr) { - return fmt.Errorf("toml: %s", strictErr.Error()) + 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) error { +func enhanceDecodeError(err error, originalContent []byte, includeLine bool) error { var typeErr *json.UnmarshalTypeError if errors.As(err, &typeErr) && typeErr.Field != "" { - 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) + 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) + } } return fmt.Errorf("field \"%s\": cannot unmarshal %s into %s", typeErr.Field, typeErr.Value, typeErr.Type) } @@ -244,6 +248,10 @@ func enhanceDecodeError(err error, originalContent []byte) error { // findFieldLineInContent searches the original config content for a field name // and returns the 1-indexed line number where it appears, or 0 if not found. func findFieldLineInContent(content []byte, fieldPath string) int { + if fieldPath == "" { + return 0 + } + // Use the last component of the field path (e.g. "proxies" from "proxies" or // "protocol" from "transport.protocol"). parts := strings.Split(fieldPath, ".") diff --git a/pkg/config/load_test.go b/pkg/config/load_test.go index 9f2f5a9f..b711a5c1 100644 --- a/pkg/config/load_test.go +++ b/pkg/config/load_test.go @@ -496,7 +496,7 @@ serverPort: 7000 require.Equal(7000, clientCfg.ServerPort) } -func TestTOMLSyntaxErrorWithLineNumber(t *testing.T) { +func TestTOMLSyntaxErrorWithPosition(t *testing.T) { require := require.New(t) // TOML with syntax error (unclosed table array header) @@ -510,8 +510,9 @@ name = "test" clientCfg := v1.ClientConfig{} err := LoadConfigure([]byte(content), &clientCfg, false, "toml") require.Error(err) - require.Contains(err.Error(), "line") require.Contains(err.Error(), "toml") + require.Contains(err.Error(), "line") + require.Contains(err.Error(), "column") } func TestTOMLTypeMismatchErrorWithFieldInfo(t *testing.T) { @@ -529,6 +530,7 @@ proxies = "this should be a table array" // The error should contain field info errMsg := err.Error() require.Contains(errMsg, "proxies") + require.NotContains(errMsg, "line") } func TestFindFieldLineInContent(t *testing.T) {